VISUAL C++ DLL to Show, Hide, or Toggle Point Display


This example will help you create a Visual C++ project to make an MFC DLL which can be called by Visual CADD. Once this project is finished, you can use it to develop more of your own Visual CADD tools. There is no need to create a new project the next time --just use this one and add your own new functions.

Following the recommendation of Should you use the Microsoft Foundation Classes (MFC) in Visual C++ when programming the Visual CADD API?, we will be creating an MFC DLL. As discussed in that section, link MFC DLLs can do everything that a non-MFC DLL can do, but are much more flexible in their ability to add powerful MFC features later. Once an MFC DLL is setup, it can be used for both MFC and non-MFC functions. The first three examples presented here are all non-MFC and could have been done with a standard non-MFC DLL. However, the fourth example adds an MFC-based function to the DLL, so the MFC DLL setup would be required at that time.

To start a new Visual C++ project to create an MFC DLL, you should use the Visual C++ AppWizard to create the project. In this example we will use the project name MFCVCADD (for Microsoft Foundation Classes - Visual CADD).

The following steps will create the Visual C++ project for an MFC DLL:

The first few steps invoke the Visual C++ AppWizard to create the required project files. We are statically linking to the MFC, following the recommendation in How should Visual C++ projects be setup to make MFC DLLs for Visual CADD API?. Among the project files created by the AppWizard are MFCVCADD.CPP and MFCVCADD.H, which are the main files for the MFC DLL. These main files perform various initialization required for MFC DLLs. All of their code is created automatically and we will not be adding to them.

Note that the above setup procedure assumes that we have followed the recommendation for setting up a project subdirectory tree as discussed in Are there ways to setup Visual C++ to efficiently manage Visual CADD API projects? If we follow that recommendation, then a folder called MFCVCADD will be created at the same level as the VCLib and VCInclude folders. This will be important as we use "..\" to indicate the parent directory of the MFCVCADD folder.

The VCLINK32.LIB file is required for building Visual CADD API projects in Visual C++. Visual CADD was originally written in Borland C++. The VCLINK32.LIB file allows Microsoft Visual C++ DLLs and EXEs to work properly with the Borland C++ Visual CADD API. Note that this is the first place we use the "..\" to indicate the parent directory of the MFCVCADD folder. A note or link referring back to the directory tree? If so, maybe the link can be in the previous paragraph, where we reference the section with the tree.

Lastly, this first example (and the next two) will create non-MFC functions to add to the DLL. We need a source file and header file to hold the functions and declarations that you will write. So, we create VCVCADD.CPP and VCVCADD.H for that purpose. Note that we inserted VCVCADD.CPP into the project, but not the VCVCADD.H file. The header file, VCVCADD.H, will be included in the VCVCADD.CPP file, causing it to become a dependency of that file and to be automatically inserted into the project. For more on header files and dependencies, refer to your Visual C++ documentation.

To get access to various MFC and Windows API functionality, you should include the standard MFC header in VCVCADD.CPP, as the first entry in the file:

        //      standard system includes
        #include "STDAFX.H"

Note that in C++ the "//" before text means that it is a comment, not recognized as code to be acted upon. It is good programming practice to use comments liberally to document your code, both to remind yourself later of what you were doing, and to assist others if you share your code with them.

All Visual CADD API functions must be declared in Visual C++ before they can be used. The declaration tells Visual C++ about the parameters required by the routines and which DLL contains them. The declarations can be added to your project by adding the VCMAIN32.H file to the project (which is recommended) or by typing the declarations into your VCVCADD.H header file.

The declarations in VCMAIN32.H include some Visual CADD API routines which use data types and structures which are declared in VCTYPE32.H. If you add the VCMAIN32.H to your project, you must also add the VCTYPE32.H file before it to avoid compile errors.

These should also be included in VCVCADD.CPP:

        //      Visual CADD API includes
        #include "..\VCInclude\VCTYPE32.H"
        #include "..\VCInclude\VCMAIN32.H"

The declarations of the necessary Visual CADD API routines for our example (which are already in VCMAIN32.H - do not add them to the .cpp file) are:

        extern "C" vbool WINAPI VCGetPointDisplay(short* iError);
        extern "C" void WINAPI VCSetPointDisplay(short* iError, vbool tf);

The data type vbool is defined in VCTYPE32.H as a short integer. If you choose to type the above declarations into VCVCADD.H instead of including VCMAIN32.H and VCTYPE32.H, then you also need to add the following to your VCVCADD.H file before the above declarations, in order for Visual C++ to recognize the vbool data type:

 	typedef short vbool;

Other keywords in the above declarations, such as extern, "C", WINAPI, short, * (as the indirection operator), void, and typedef are Visual C++ keywords. The reader should refer to their Visual C++ documentation for details.

Lastly, you add your project includes. They should follow the Visual CADD API includes (at the head of the .cpp file) in case they reference any of the structures defined in VCTYPE32.H.

        //      project includes
        #include "MFCVCADD.H"
        #include "VCVCADD.H"

The two point-display Visual CADD API routines (in fact, almost all Visual CADD API routines) have a parameter called iError. This is a short integer value which is returned from the routine to tell your application the success or failure of the routine when it is done. (The parameter passed is actually a pointer, and the value is returned by placing the value at that memory address.) The value returned will be 0 (zero) on success and 1 (one) on failure. Depending upon what task your application is performing, it may be very important to check the value returned to iError to verify successful completion of the routine. Any errors should be handled by your application, as appropriate.

For setting the display of points, any errors are unlikely to be critical, so this example will choose to ignore iError. In general, however, it is good programming practice to always check the return value of iError or any other return codes.

As used in the function declarations in VCMAIN32.H, iError is a pointer, not a short integer. Standard programming practice would use pError or piError to indicate a pointer, but we need to live with what is already in the Visual CADD API headers. Thus, to avoid some confusion, this example will use a short integer iErr as the error code and pErr as the pointer to it.

In C++, where you declare a variable for the first time determines which parts of the program can use that variable, and is called the scope of the variable. The variables iErr and pErr will be used throughout VCVCADD.CPP, so we want all functions throughout the entire file to be able to access them. To do this, we declare these variables at the beginning of VCVCADD.CPP, before all the functions. Such variables are said to be declared with file scope and the variables are called global variables. Because global variables are assumed to be external (accessible by other files in the same project), we also specify static to force only internal (this file only) access. In a later example, we will use external variables.

Type the following after your project includes:

         //      local variables
        static short  iErr;              //      Visual CADD error code
        static short* pErr = &iErr;     //      ptr to Visual CADD error code

Note that pErr is a pointer and is declared with *, the indirection operator. It is initialized with the address of iErr using &, the address-of operator. Pointers and address-of are frequently used in C++ programming. The reader should refer to their Visual C++ documentation for more information.

Now that our "overhead" is done, we can add the actual functions to control the display of points. In VCVCADD.CPP, add the following:

        //      HidePoints
        HRESULT WINAPI HidePoints(void)
        {
                VCSetPointDisplay(pErr,0);
                return(NOERROR);
        }

        //      ShowPoints
        HRESULT WINAPI ShowPoints(void)
        {
                VCSetPointDisplay(pErr,1);
                return(NOERROR);
        }

        //      TogglePoints
        HRESULT WINAPI TogglePoints(void)
        {
                VCSetPointDisplay(pErr,1 - VCGetPointDisplay(pErr));
                return(NOERROR);
        }

It is common practice for DLL functions to return an HRESULT (32-bit long integer) error code to the calling program. Although Visual CADD does not check the return values of DLL functions, at some time you may choose to call your functions from other programs where error-checking is useful. Thus, this example has chosen to return an HRESULT. NOERROR is defined in a standard Windows header (WINERROR.H) and is used when no error has occurred.

Visual CADD uses the _stdcall calling convention for functions. In Visual C++, _cdecl is the default calling convention, so the DLL functions must be explicitly declared as _stdcall. The examples will use the WINAPI macro (provided by Visual C++ in WINDOWS.H) which translates to _stdcall.

The function declarations must be added to VCVCADD.H. Function declarations tell the Visual C++ compiler about the calling conventions, parameters, and return values of the functions. If other source files will call your functions, those source files will need to know this information. This information is passed to other source files by having those source files include the VCVCADD.H header file.

Strictly speaking, because VCVCADD.CPP is the only source file in this project which uses (in fact, defines) these functions, it is not mandatory that the function declarations be added to the VCVCADD.H file. However, it is accepted as good programming practice to do so and can occasionally help to catch typos and mis-specified data types.

So, it is recommended that you add the following to VCVCADD.H:

        HRESULT WINAPI HidePoints(void);
        HRESULT WINAPI ShowPoints(void);
        HRESULT WINAPI TogglePoints(void);   

Lastly, the function names need to be exported by adding them to the EXPORTS section of the module definition file MFCVCADD.DEF. Module definition files contain information about how Visual C++ will create an EXE or DLL (in our case). The project build settings (available from the Visual C++ menu, Build, Settings) control most of what Visual C++ needs to build the DLL, but additional settings are controlled in the module definition file. Functions can be made available only to other parts of your project, or they can be exported to make them available to other programs, such as Visual CADD. Exporting functions is one of the things which can be controlled in the module definition file by adding the function names to the EXPORTS section of MFCVCADD.DEF:

        HidePoints
        ShowPoints
        TogglePoints

The Visual CADD API routine VCSetPointDisplay does nothing more than turn the display of points on and off. When passed a 0 (zero), it turns the display off. When passed a 1 (one), it turns the display on.

The Visual CADD API routine VCGetPointDisplay tells you whether the display of points is on or off. If it returns 0 (zero), it is off. If it returns 1 (one), it is on. If you subtract this value from 1 (one), you can toggle between 0 and 1. If it was 0 ,you get 1, and if it was 1, you get 0. The subtraction from 1 is a standard trick for toggling 0 and 1 and is what TogglePoint uses as a parameter in VCSetPointDisplay to turn on-to-off and off-to-on.

The final step is to create the DLL using Build, Build MFCVCADD command in Visual C++. Your DLL will be named MFCVCADD.DLL, for Microsoft Foundation Classes - Visual CADD.

If this is your first time doing a Build, and you get fatal errors, do not despair. Even the most experienced programmers find that simple spelling or syntax errors (i.e., you left a space where there should not have been one) cause the majority of problems. Also, the first error often triggers others --you may find that correcting the first one will cause the others to vanish. If problems persist, retrace your steps, make sure your support files are in the right path, and use your C++ online help.

To run your DLL, include the following in your CMDEXT.DEF (recommended) or Assign Script (AS), where the first line of each is omitted for scripts.

        HidePoints,HP, ,Hide Points,Hide Points,
                DllName;C:\VC++4\MFCVCADD\RELEASE\MFCVCADD.DLL;
                DllFunName;HidePoints;DllRun;Regen;

        ShowPoints,OP, ,Show Points,Show Points,
                DllName;C:\VC++4\MFCVCADD\RELEASE\MFCVCADD.DLL;
                DllFunName;ShowPoints;DllRun;Regen;

        TogglePoints,GP, ,Toggle Points,Toggle Points,
                DllName;C:\VC++4\MFCVCADD\RELEASE\MFCVCADD.DLL;
                DllFunName;TogglePoints;DllRun;Regen;

Now, from Visual CADD, HP will hide points, OP will show points, and GP will toggle points.

Suggested Additions to the Example DLLs The display of points is only one of several properties which cannot be controlled through scripts or two-letter alias commands defined in the CMDEXT.DEF. Others which may be included in a your DLL are:


Programming Index | VB and VC++ Setup | Example 1 Overview | Next Tutorial