Rules for Compiling DLL Code Versus Non-DLL Code

To create a complex DLL or DLL application, you must decide which source files should be compiled as DLL code and which should be compiled as non-DLL code. The following is a list of the rules for making that decision:

  1. A source file that contains a function call through a pointer that may point to either a function or function descriptor must be compiled as non-DLL code. For example, the qsort() routine in Figure 4 must be compiled as non-DLL code, because qsort() gets a pointer to a function to call. Because that pointer can be to a function compiled as either DLL code or non-DLL code, the qsort() routine emitted by the compiler cannot tell whether the routine to invoke is DLL or non-DLL code. This means that qsort() must be non-DLL. For additional information about function pointers, see Pointer Assignment.
  2. A source file that calls imported functions or imported variables by name must be compiled as DLL code.
  3. A source file that contains a comparison of function pointers that may be DLL function pointers must be compiled as DLL code.

    The comparisons shown in Function Pointer Comparison in Non-DLL Code are undefined. To obtain valid comparisons, you must compile the same source files as DLL code.

  4. A source file that may pass a function pointer to DLL code through a parameter or a return value must be compiled as DLL code.

    If the qsort() routine in Figure 4 is compiled as DLL code instead of non-DLL code, non-DLL applications can no longer call it. To be able to call the DLL code version of qsort(), the original non-DLL application must be recompiled as DLL code.

  5. A source file that may pass a function pointer to DLL code by linking the references to the definition of an external variable must be compiled as DLL code.

    In the following examples, if source file 1 has been compiled as DLL code, source file 2 must be compiled as DLL code as well.

    1. File 1:
      void main(void) {
        goo();           /* initialize fp to be hello function */
        fp();            /* call hello function                */
      }
    2. File 2:
      extern void (*fp)(void);
      void hello(void) {
        printf("hello\n");
      }
      void goo(void) {
        fp = hello;
      }

      If you do not use the DLL compiler option, fp would contain the address of hello. File 1 would expect fp to contain a function descriptor for fp, and the execution of fp would abend.

You must comply with all the rules described above when creating a complex DLL or DLL application. The prelinker flags violations of rule 2 as an error, but the compiler and prelinker do not indicate any other rule violations.

Note: A DLL or DLL application that does not comply with these rules may produce undefined run-time behavior. For a detailed explanation of incompatibilities between DLL and non-DLL code, see Compatibility Issues between DLL and Non-DLL Code.

To comply with the DLL rules, you should also be aware of the following:

  1. A C source file will be compiled as DLL code if the DLL compiler option is on.
  2. A C source file will be compiled as non-DLL code if the NODLL compiler option is on.
  3. Other types of source files can be compiled only as non-DLL code.