Maya - Loading the C++ API

In order to use the C++ API you will have to include the header MaxwellMayaAPI.h. This file is copied in Maya's include directory when the plug-in is installed, so if your project already has the correct preprocessor paths for using the Maya SDK, you can just do #include <MaxwellMayaAPI.h> without making any changes to the project.

The API is designed in such a way that the calling code does not have any static dependencies on symbols in the Maxwell plug-in. It is often the case that a plug-in wants to expose features to Maxwell, but still has to load and function when the Maxwell plug-in is not present. In order to achieve this, you must be able to load the API dynamically, but dynamic loading for regular C++ classes is difficult at best. The solution is to expose a single entry point function which is loaded dynamically and then call that function to obtain a pointer to an abstract interface. The rest of the method calls will go through the vtable of the interface class, so no static dependencies are added to your plug-in.

The entry point function is called GetMaxwellMayaAPI and its prototype is:

MaxwellMayaAPIInitStatus GetMaxwellMayaAPI(int version, MaxwellMayaAPI** api);

In order to obtain the API interface, you load the Maxwell plug-in shared library, retrieve the GetMaxwellMayaAPI function pointer and call it. For example, on Windows you would do:

HMODULE mod = LoadLibrary("maxwell.mll");
if(!mod) { /* error handling */ }
// GetMaxwellMayaAPIProc is defined in MaxwellMayaAPI.h.
GetMaxwellMayaAPIProc entryPoint = (GetMaxwellMayaAPIProc)GetProcAddress(mod, "GetMaxwellMayaAPI");
if(!entryPoint) { /* error handling */ }
MaxwellMayaAPI* api = NULL;
MaxwellMayaAPIInitStatus initStatus = entryPoint(MAXWELL_MAYA_API_VERSION, &api);
if(initStatus != MaxwellMayaAPIInitStatus_OK) { /* error handling */ }
// We can safely decrement the usage count on the library now, since the Maxwell plug-in is loaded
// by Maya too,
 so this will not unload the code.
FreeLibrary(mod);

The possible return codes from the entry point function are:

  • MaxwellMayaAPIInitStatus_OK: the call succeeded.
  • MaxwellMayaAPIInitStatus_IncompatibleVersion: the version number passed to the function is incompatible with the installed Maya plug-in.
  • MaxwellMayaAPIInitStatus_NotLoaded: the Maxwell plug-in is not loaded in Maya. This error will occur if the Maxwell plug-in is not enabled in the plug-in manager, but the LoadLibrary() or dlopen() call somehow found and loaded the file (instead of returning a handle to the file previously loaded by Maya).

If the function fails, the API interface pointer will also be set to NULL. The MaxwellMayaAPI class contains a static inline method called LoadAPI() which handles all the details of opening the Maxwell plug-in and querying the interface pointer on all supported platforms. This method will return NULL if an error occurs. If you want to load and call the entry point yourself and do not want LoadAPI() to be declared, define the macro MAXWELL_MAYA_NO_LOAD_HELPER before including MaxwellMayaAPI.h.

The version number passed to the entry point function helps detect incompatibilities between binaries. Always pass the macro MAXWELL_MAYA_API_VERSION for the version parameter. If a user installs a newer (or older) Maxwell plug-in which exposes an incompatible API, this check will prevent your code from getting an interface with a different vtable layout than that declared in the header file you used to build your plug-in (since trying to use such a pointer will most likely crash Maya).

The API version number is incremented each time an addition is made in one of the API classes. Normally this does not break backwards compatibility; your existing binaries will still work with the updated Maxwell plug-in. The entry point function will recognize that the version number your binaries are sending is still compatible, even though it's not the latest. However, if you recompile your code with the newer header, your plug-in will no longer work with previous versions of the Maxwell plug-in.

In rare occasions we will have to make changes which will break backwards compatibility. In this case, the version check inside the entry point function will fail for existing binaries and they won't get an interface pointer, so you will have to recompile your plug-in if you want it to work with the updated Maxwell plug-in.

It may be tempting to load the Maxwell API in the initializePlugin() function of your plug-in, but that is not a robust approach. The Maxwell plug-in may not be loaded yet when your plug-in is initialized, especially if both are set to autoload (Maya does not guarantee the initialization order). It is better to obtain the API pointer when your command is run and cache it if the call succeeds, because it's probably Maxwell that's running your command, and then you know it's present. You must still be prepared for the load call to fail, either because the version is incorrect, or because the user manually ran your command for some reason.

Caching the API pointer may be an issue if the Maxwell plug-in is unloaded and then reloaded by the user. However, at this time it is not possible to unload Maxwell due to some limitations in the Maya API, so this problem does not exist in practice. If unloading will be supported in the future, we will add a mechanism for validating the interface pointer, so you know when you have to reopen the API.