Windows Programming


Windows, DLLs, and Floating Point Types

William Smith


William Smith is the engineering manager at Montana Software, a software development company specializing in custom applications for MS-DOS and Windows. You may contact him by mail at P.O. Box 663, Bozeman, MT 59771-0663.

While DLLs are largely language independent, conventions for passing floating point values remain compiler dependent — largely because Windows sets no explicit standards for representing floating point values. Parameter passing methods vary, depending upon calling convention, floating-point type, and even compiler vendor. When you develop programs and DLLs with different compilers, you must be certain that both the argument passing methods and function return methods match between program and DLL. When the DLL exports functions that pass floating-point values, the program and DLL may be incompatible, unless both use a specific floating-point type and calling convention.

In this article, I will describe parameter passing incompatibilities between two compilers — Microsoft C/C++ 7.0 (MSC) and Borland C/C++ 3.1 (BC). If you are using other compilers, you may want check them for incompatibilities.

Calling Conventions

MSC and BC offer three alternate calling methods: _cdecl, _fastcall, and _pascal (_fortran is the same as _pascal). _cdecl is the standard C method of passing parameters right to left on the stack. _fastcall uses registers, when possible, to pass parameters. _pascal passes parameters left to right on the stack. For each of these calling conventions, the two compilers use identical mechanisms for passing argument values.

The calling convention also controls how the compiler passes return values. Surprisingly, for certain calling conventions, the two compilers use different mechanisms for passing return values.

Table 1 and Table 2 show how the compilers return floating-point values from functions. The unshaded portions of the tables represent parameter return methods that are identical between the two compilers. Both compilers use the NDP (Numeric Data Processor) stack to return floating-point values when the functions are defined with the _fastcall calling convention. Also, under the _cdecl calling convention both compilers use the NDP stack to return long doubles. However, if you are "mixing" compilers and exporting DLL functions which return a floating-point value, only the latter combination — the long double return type with the _cdecl calling convention — will work. _fastcall will not work, because exported DLL functions must be declared as far, and _fastcall is incompatible with far functions.

If you don't want to use the long double return type, an alternative is to build the DLL with the same compiler that was used to compile the program. This alternative may be inconvenient: if you are selling your DLLs, you will have to distribute two versions — one for programs compiled with MSC, and one for programs compiled with BC.

The last alternative is to return floating-point types through pointers. You must use this alternative if you don't know which compiler will be used to compile the calling program, or if you know that the compiler to be used employs an incompatible parameter passing method.

Summary

You may need to use special techniques to pass floating-point parameters between programs and DLLs. These techniques include appropriate selection of return type, calling convention, and compiler. You must use one of three techniques when the DLL exports functions which pass floating point parameters.

Returning Structures from Exported DLL Functions

As with floating-point numbers, MSC and BC do not use the same mechanisms to return structures from functions.
Table 3 shows the return mechanism used by MSC and BC under the calling conventions _cdecl, _fastcall, and _pascal. While MSC returns a pointer into the data segment or stack segment, BC always returns a far pointer. If you can't guarantee that the DLL and calling program will be compiled with the same compiler, the DLL must not return structures from exported functions.