Dealing with #defines in IDL Files

This page describes why symbols defined with a #define disappear from the MIDL compiler generated H files, and what can be done about it. This explanation applies to any files processed by MIDL, such as *.idl, *.acf, *.h files.

The disappearance of #define symbols is a result of MIDL delegating the preprocessing of input files to a preprocessor. By default, the preprocessor is a C/C++ preprocessor from the build environment. After preprocessing, the input stream MIDL receives has only #line preprocessor directives. In particular, the preprocessor unrolls all macro definitions in input files, and therefore, MIDL cannot detect their presence. Consequently, when MIDL replicates type definitions from an input file to the generated H file, the #defines are not replicated. Therefore, do not use #defines directly in IDL files if they are to be used later from the generated H file.

The following four workarounds are recommended:

  • Use the const declaration specification.
  • Use separate header files that are imported or included in the IDL file, and later included in the C-source code.
  • Use enumeration constants in the IDL file.
  • Use cpp_quote to reproduce #define in the generated header file.

You can reproduce manifest constants using the IDL constant-declaration syntax. Note that the const in the IDL constant-declaration is different from C/C++ const semantics, and simply introduces a named constant for an IDL compilation. For example:

const short ARRSIZE = 10

This example specifies that ARRSIZE is a constant with a value of 10. Named constants can be used in IDL array declarators and other places where a C programmer would use a manifest defines. In addition, this syntax results in the following line being generated in the header file:

#define ARRSIZE 10

Another way to handle **#**define statements is to package them in a separate header file, either into a file devoted to **#**define statements or into a file that contains only type definitions. A file that contains only preprocessor directives may be safely included both by the IDL file and the C-source files. Although the directives will not be available in the header file generated by the MIDL compiler, the C-source program can include the separate header file. In a similar fashion, a header file with **#**define statements and regular type definitions can be imported from your IDL file. This approach encapsulates the **#**define and typedef statements by using them in an H file such that the **#**define symbols are not used in the importing IDL file directly. Importing a header or IDL file to another IDL file prevents the typedef statements from being replicated to the H file generated by MIDL (which is in contrast to **#**include statements). This approach allows the original header file to be safely referenced from the C code along the generated H file without having a problem with duplicated definitions.

Use of enumeration constants in the IDL file is also effective. These constants can be used in constant expressions in IDL, for example, in array declarators. Enumeration constants are not removed during the early phases of MIDL compilation by the C-compiler preprocessor, so enumeration constants are available in the header file generated by the MIDL compiler. Consider the following statement:

typedef enum midlworkaround { MAXSTRINGCOUNT = 300 };

This statement will not be removed during MIDL compilation by the C preprocessor and the typedef will be replicated to the generated H file. The constant MAXSTRINGCOUNT is available to C-source programs that include the header file generated by the MIDL compiler.

Finally, the cpp_quote directive of MIDL can be used to write out an arbitrary string directly into the generated H file. For example, to get the manifest constant used previously on this page with cpp_quote, the following statement can be used:

cpp_quote ("#define ARRSIZE 10")

This statement results in the following line being generated in the header file:

#define ARRSIZE 10