Win32 Calling Conventions

Win32 calling conventions

The 32-bit Windows environment (Win32) supports several calling conventions that influence the precise manner in which arguments are passed to a function, and how the return value must be retrieved. When calling an external function or procedure in this environment, AIMMS will always assume the WINAPI calling convention. The following macro in C makes sure that the WINAPI calling convention is used. That same macro also makes sure that the function or procedure is automatically exported from the DLL.

#include <windows.h>
#define DLL_EXPORT(type) __declspec(dllexport) type WINAPI

You can add this macro to the implementation of any function that you want to call from within AIMMS, as illustrated below.

DLL_EXPORT(double) Cobb_Douglas( int n, double *a, double *c )
{
    /* Implementation of Cobb_Douglas goes here */
}

Prevent ++ name mangling

By default, ++ compilers will perform a process referred to as name mangling, modifying each function name in your source code according to its prototype. By doing this, ++ is able to deal with the same function name defined for different argument types. If you want to export a DLL function to AIMMS, however, you must prevent name mangling to take place, ensuring that AIMMS can find the exported function name within the DLL. You can do this by declaring the prototype of the function using the following macro, which accounts for both C and ++.

#ifdef __cplusplus
#define DLL_EXPORT_PROTO(type) extern "C" __declspec(dllexport) type WINAPI
#else
#define DLL_EXPORT_PROTO(type) extern __declspec(dllexport) type WINAPI
#endif

Thus, to make sure that a ++ implementation of Cobb_Douglas is exported without name mangling, declare its prototype as follows before providing the function implementation.

DLL_EXPORT_PROTO(double) Cobb_Douglas( int n, double *a, double *c );

Function declarations like this are usually stored in a separate header file. Note that along with this prototype declaration, you must still use the DLL_EXPORT macro in the implementation of Cobb_Douglas.

DLL initialization

When your external DLL requires initialization statements to be executed when the DLL is loaded, or requires the execution of some cleanup statements when the DLL is closed, you can accomplish this by adding a function DllMain to your DLL. When the linker finds a function named DllMain in your DLL, it will execute this function when opening and closing the DLL. The following example provides a skeleton DllMain implementation which you can directly copy into your DLL source code.

#include <windows.h>

BOOL WINAPI DllMain(HINSTANCE hdll, DWORD reason, LPVOID reserved)
{
    switch( reason ) {
       case DLL_THREAD_ATTACH:
           break;
       case DLL_PROCESS_ATTACH:
           /* Your DLL initialization code goes here */
           break;
       case DLL_THREAD_DETACH:
           break;
       case DLL_PROCESS_DETACH:
           /* Your DLL exit code goes here */
           break;
    }
    return 1; /* Return 0 in case of an error */
}

To prevent name mangling to take place, you can best declare the function DllMain as follows.

#ifdef __cplusplus
extern "C" BOOL WINAPI DllMain(HINSTANCE hdll, DWORD reason, LPVOID reserved);
#else
BOOL WINAPI DllMain(HINSTANCE hdll, DWORD reason, LPVOID reserved);
#endif