Fixing Differences Between C and C++

At this point, your C source files are in the project but not yet integrated into the MFC sources. Before taking further integration steps, you need to make your old C code compile as C++ code. When you build the MFC project, you'll encounter errors that stem either from the differences between C and C++ or from header incompatibilities. Build the project at this point. Then fix the errors.

For SHOWDIB, the great majority of the errors at this stage are type conversion problems. The main categories of errors encountered include:

Note The 16-bit version of SHOWDIB happens to use old-style function headers. So you should change all of the function headers in the original SHOWDIB .C files to use ANSI-style headers. This shortens the error list a great deal.

Scope Problems

As you work through the migration, you'll find a number of variables in the moved code that lose their moorings. You get linker or compiler errors because the variables are undefined in SHOWD.CPP. Sooner or later, you'll need the following declarations in SHOWDIB.H:


extern HINSTANCE hInst ; extern BOOL bNoUgly; extern WORD UpdateCount; extern BOOL bUpdateColors; extern UINT nAnimating; extern PLOGPALETTE pLogPal; extern CHAR szBitmapExt[]; // for 16 bit, use char extern HPALETTE hpalSave; extern BOOL bMemoryDIB; // add for 16-bit SHOWDIB

When you add these entries for 16-bit SHOWDIB, also make the following changes in SHOWDIB.CPP to match the data types listed above:

C++ is stricter than C about variable declarations and definitions. A variable definition causes storage to be allocated. A variable declaration, using extern, does not. It merely promises that a real definition exists somewhere in the program. The linker will manage the connection.

In SHOWDIB, these problem variables must be visible in various modules of the program — hence the extern declarations in SHOWDIB.H, which affected modules can include as needed. The variables must also be defined in some module, as most now are in SHOWDIB.CPP.

Type Conversion Problems

Numerous errors in both versions of SHOWDIB result, for example, from lines like the following (error code C2446):


lpbi = (VOID FAR *)GlobalLock(hbiCurrent);

where the VOID FAR* cast requires a more precise data type in C++:


lpbi = (LPBITMAPINFOHEADER)GlobalLock(hbiCurrent);

Similar type conversion problems occur in passing parameters, accounting for another large group of errors. In most cases, an improved type cast takes care of the problem, although actually changing variable or parameter types might be even better.

Use of Obsolete Functions

This accounts for only a few errors. For example, both versions of SHOWDIB use the MakeProcInstance function, which is obsolete in Win32:


lpfnPrintDlgProc = (DLGPROC) MakeProcInstance (PrintDlgProc, hInst); lpfnAbortProc = (WNDPROC) MakeProcInstance (AbortProc, hInst);

It's no longer necessary in Win32 to call MakeProcInstance (and often not necessary in 16-bit Windows, for that matter). The flat, unsegmented address space of Win32 makes it unnecessary to perform the data-segment switching "trick" the function used to perform. MakeProcInstance is a macro in Win32 that the preprocessor treats as just what you give it.

You can handle the occurrence of MakeProcInstance in SHOWDIB in two ways. The quick (but not pretty) way, which works for both versions, is to change some casts in the existing calls:


lpfnPrintDlgProc = (FARPROC) MakeProcInstance ((FARPROC)PrintDlgProc, hInst); lpfnAbortProc = (FARPROC) MakeProcInstance ((FARPROC)AbortProc, hInst);

In the 16-bit version of SHOWDIB, cast the second parameter in each call to HINSTANCE.

Inelegant Errors

Occasionally, code is somewhat less than elegant, as the translation process can reveal. In one place, SHOWDIB uses the cast to int in line 3 below:


if (bDIBToDevice) { (int)hMemDC = 1; // won't compile under C++ break; } ... if (!(hMemDC = CreateCompatibleDC (hDC))) ... if (!hMemDC) ...

In the 16-bit version, the cast to int is missing, so the error message is different, but the correction described below is still the answer. The 16-bit version requires more precise data types: assigning an integer to an HDC doesn't work in C++. For the 32-bit version, C++ doesn't allow the cast on the left side of an assignment; the language doesn't interpret the expression:


(int)hMemDC

(where hMemDC is of type HDC) as an l-value. A quick fix is the following:


hMemDC = (HDC)1; // will compile, but not pretty

The original code (and the quick fix) is dubious at best. The hMemDC variable, an HDC, is used as a Boolean condition in the final if statement ¾ if the DC has been successfully allocated, or if the flag bDIBToDevice is true (and hMemDC gets set to 1), hMemDC is nonzero, and this value is used in the final if statement. It would be better to revise the code to use another Boolean flag and avoid using an HDC this way.

Additional Errors in the 16-Bit Version of SHOWDIB

Most of the errors discussed in previous categories apply to the 32-bit version of SHOWDIB or to both versions. The 16-bit version produces a few other problems.

The IDM_ABOUT case for the WM_COMMAND message uses a dialog template resource ID no longer defined in the C++ project. To correct this, change the first parameter in the fDialog function call below from "ABOUT" to "IDD_ABOUTBOX":


case IDM_ABOUT: /* Show About .. box */ fDialog (IDD_ABOUTBOX, hWnd,AppAbout); break;

A better improvement would be to remove that code and use the MFC About dialog box mechanism, but this simple fix will do. Also cast the last parameter to FARPROC.

Due to a bug in the 16-bit version, you need to remove the IDM_ANIMATE20 case in the WM_COMMAND code. There is no such case, and the identifier is undefined in the C++ version.

The following error in the 16-bit version:


c:\showd6\print.cpp(37) : error C2128: 'AbortProc' : alloc_text/same_seg applicable only to functions with C linkage

occurs because the following compiler-specific code is not supported under C++:


#pragma alloc_text(_PRINT, AbortProc, PrintDlgProc)

You could specify C linkage for the two functions using extern "C":


extern "C" AbortProc extern "C" PrintDlgProc

But the more portable solution, in case you ever plan to migrate the application to 32 bit, is simply to delete the line.

The 16-bit version of SHOWDIB uses an assembler module for a special version of the chdir function. Bearing in mind that you might also want to port the 16-bit application to 32 bit at some point, now is the time to adopt a portable solution. In this case, the function written in assembler has a counterpart in the C run-time library: the _chdir function. To use the portable version:

1. In the file DLGOPEN.CPP, remove the following line:


extern PASCAL chdir(LPSTR); /* in dlgopena.asm */

2. In the same file, replace the following line:


if (chdir ((LPSTR)szFileName))

with:


if (_chdir (szFileName))

If your own programs use assembler modules, you should seriously consider rewriting them in C++ to ease future portability to 32 bit.

Once you have fixed all errors, you can begin integrating your code into the MFC skeleton. If you run the application now, you see the SHOWDIB user interface, but all menus are disabled. You'll fix that shortly.