
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.
Defining the DDERAYDATA structure
The ZCLIENT C-code defines a data structure named DDERAYDATA that is passed by reference by the PostArrayTraceMessage function for faster, more efficient ray tracing. The C-code for this is shown below:
typedef struct{
double x, y, z, l, m, n, opd, intensity;
double Exr, Exi, Eyr, Eyi, Ezr, Ezi;
int wave, error, vigcode, want_opd;
}DDERAYDATA; The structure consists of 14 double-precision words, each of length 8 bytes and 4 signed integer words, each of length 4 bytes. These memory bytes will appear in exactly the above order in memory. This structure must be matched on the FORTRAN side by a user-defined type with exactly the same sequence of memory bytes. The FORTRAN code for this will be shown later. An array of such structures is expected to be supplied as an argument to the PostArrayTraceMessage function, in number one more than the number of rays to be traced (see the ZEMAX manual for details of how the first element of this array is used to set flags).

!DEC$ ATTRIBUTES C, REFERENCE, ALIAS:'_PostRequestMessage' :: PostRequestMessageThe attributes “C, REFERENCE” are required when ‘__cdecl’ is used on the C++ side.


I found that the following works (access to an integrated development environment such as Microsoft Developer Studio is assumed here):
Here is a screen shot of the way the ZCLIENT.CPP file is included in a project called ‘userfunc’ and then compiled. In this case, the Microsoft Visual C++ 6.0 compiler and the Compaq Visual Fortran are integrated into the Microsoft Developer Studio environment, so, depending on the file extension (.C, .CPP, .F90 .FOR etc), the appropriate compiler is invoked.
Here is a screen shot showing how the FORTRAN project called ‘Hellofunc’ is organised. In this case the executable file has been given the name HELLOFUNC.EXE:

NEWSTRING = OLDSTRING(1:LENGTH)//CHAR(0)On the other hand, when receiving and wishing to use character strings returned by one of the C-functions defined in ZCLIENT, one must be aware of the ‘null’ character that appears at the end of them and one should strip it off before using an internal read to convert a character string containing the digits of a number into a real or integer data item.


The graphic window will remain displayed, even when the extension is terminated, until it is closed by the user. The HELLOFUNC extension can be active or not, with the graphic displayed, and if you click on ‘Update’ or ‘Settings’ menu items, another instance of the extension is started, so the ‘settings’ flag, stored by ZEMAX and associated with the window, is sent back to the new instance of the extension and is used, in the present case, to sense and quit this new instance, displaying the message that ‘This window has no options’. On the left below is the message displayed by the extension when the ‘Update’ menu item is pressed. On the right is that shown when the ‘Settings’ menu item is selected and the ‘Options’ flag is set to ‘1’ by ZEMAX.

Otherwise the extension could just regenerate new data for the plot window, based on the ‘settings’ data that ZEMAX received when it got the ‘MakeGraphicWindow’ command and which it reflects back to the extension when the appropriate menu item is selected. Note that before any instance of the extension is terminated, the DDE item ‘ReleaseWindow’ is and must be sent, in order to release control of the graphics window. The following is the message sent using PostRequestMessage:
A message box (on the right above) is programmed to appear giving the return code from this command, which is just the number displayed in the top left hand corner of the graphics window shown earlier. This number would be ‘0’ if no window had been displayed before the request to ‘ReleaseWindow’ was made. Refer to the ZEMAX manual for full details on extension-generated graphic and text windows and their settings.
Note that an extension can open and maintain only one graphic window, as only a single temporary filename is supplied to the extension by ZEMAX. You can have as many extensions as you like running, and they can all have their own windows, but only one window is allowed per instance of the extension. This is just the way ZEMAX works. For example, when you open a ray fan plot you don't get two windows, just one.
If an extension wanted to show more than one graph or text listing, then the workaround is for the extension to make the selection of which data to present one of the settings, like ZEMAX does to choose between false color and contour maps for example. The extension could even create multiple displays, and then store them for rapid re-display when the user selects the alternate display.