- Home
- User Articles
- How To Write ZEMAX Extensions in FORTRAN
- Home
- Programming ZEMAX
- Extensions
- How To Write ZEMAX Extensions in FORTRAN
How To Write ZEMAX Extensions in FORTRAN
- By Anthony Richards
- Published 22 June 2006
- User Articles , Extensions
-
Rating:




Modifying and Compiling the C-Code 1
The main reason for modifying the ZCLIENT C-code is to control the calling convention used and the declaration of the names, or symbols, of each callable function or routine. When compiling in C, the compiler produces an .OBJ file that contains, among other things, a ‘symbol table’, a table of those functions that have been defined or referenced in the code, such as subroutines (C ‘void’ functions) and functions. Before we can successfully link this C .OBJ file with an .OBJ file compiled from FORTRAN code that calls some of the C-functions, the FORTRAN compiler must generate identical symbols for the C-functions so that the linker will find them in the ZCLIENT.OBJ file. The linker will search default C libraries for any symbols that it does not recognize within supplied .OBJ files.
The symbols may be either straightforward or quite complicated. For example, a function called ‘PostRequestMessage’ defined in the C-code might, if compiled as C-code (which the Microsoft C++ compiler would automatically assume it to be if it exists in a file having extension ‘.C’) appear in the symbol table with the name ‘_PostRequestMessage’, that is, it would just have a leading underscore added. However, if the same code is included in a file with ‘.CPP’ extension, then the C++ compiler would produce a symbol of the form ‘?PostRequestMessage@@YAHPAD0@Z’. The apparently superfluous additional leading and trailing characters result from a process called ‘name mangling’ which is a scheme particular to the Microsoft C++ compiler. There is a structure to this name mangling (try Googling ‘name mangling C++’ for information on this if you wish), but the main thing to be aware of is that it might change in future (Microsoft being what it is!). There is a Microsoft utility DUMPBIN (shipped with most FORTRAN and C compilers or available from the MS Windows® SDK) that can be used to extract the list of symbols in any .OBJ file (be it generated by a C-compiler or a FORTRAN one) so in theory one could extract the symbol in ZCLIENT.OBJ that we need and then give our FORTRAN equivalents the same names (with due regard being paid to case). But, because the compiled symbols may change in future (because of possible name mangling changes etc.), it is much better to control the symbol by using the C language term ‘extern’.
Here is the original ZCLIENT code for the main functions used to pass data across the DDE interface, followed by the modified code using ‘extern’:

Note that the UserFunction name has been made uppercase in the modified code. This means that all references to it in the C-code (there is only one other reference to it, inside the main window procedure WndProc) must also be made uppercase, since C preserves case. For the benefit of FORTRAN programmers, the presence of an asterisk ‘*’ in front of an argument, such as ‘char *szBuffer’ defines a pointer to the argument, the address of the memory location containing the argument’s value. This is equivalent to the FORTRAN ‘pass by reference’. Arguments without the leading ‘*’ are passed by value. The calling convention ‘__cdecl’ (the default in C++) ensures that the calling function cleans up the stack, where arguments are temporarily placed during function calls, and that the generated symbols only have a leading underscore added to the function name, with case preserved (If the stack is not properly ‘cleaned up’ the program would likely crash uncontrollably).
The ‘mangled’ naming referred to earlier is just a coded form of the function declarators given in the ‘original’ box above, so in theory, with access to the ‘name mangling’ convention, one could reconstruct (‘demangle’) the function declarator from its mangled name obtained using DUMPBIN from the .OBJ file containing the function, thus giving one knowledge of the type of function, the type and number of arguments and how the C program is passing the arguments (by value or by reference).
When the above modified code is compiled, we finish up with a ZCLIENT.OBJ file that contains, among others, the following straightforward symbols:
These are the names (preserving case) that the FORTRAN compiler must generate when wishing to call the first three C-functions and when expecting a call for the fourth function from the C function WndProc.