Open Search
    Plugin Messages

    About

    Cinema 4D communicates with a loaded plugin (cdl64 or dylib file) by calling three basic functions that have to be implemented by that plugin. Typically these functions are implemented in the plugin's main.cpp file.

    • PluginStart(): This function is called when the plugin is loaded. Typically the plugin classes are registered here.
    • PluginMessage(): This function is called several times during startup, shutdown and while Cinema 4D is running.
    • PluginEnd(): This function is called when the plugin is unloaded.

    Order

    Several messages are sent to PluginMessage(). The order in which these messages are sent and the order in which the functions are called is the following:

    Startup:

    Events during runtime:

    • Message C4DPL_DEVICECHANGE is sent when a device was added to or removed from the machine.

    Shutdown:

    For the full list of messages see C4DPL_MESSAGES.

    PluginStart

    PluginStart() will be called after Cinema 4D loaded the plugin. Typically custom plugin classes are installed here using the corresponding "Register" function. PluginStart() may also be the right place to start a background thread or to check the validity of a keyfile.

    {
    // register plugins
    const Bool success = RegisterObjectPlugin(123456, "Example Generator", OBJECT_GENERATOR, ExampleGenerator::Alloc, "Oexamplegenerator", nullptr, 0);
    if (!success)
    return false;
    return true;
    }
    Bool RegisterObjectPlugin(Int32 id, const maxon::String &str, Int32 info, DataAllocator *g, const maxon::String &description, BaseBitmap *icon, Int32 disklevel)
    Bool PluginStart()
    maxon::Bool Bool
    Definition: ge_sys_math.h:51
    #define OBJECT_GENERATOR
    Generator object. Produces a polygonal or spline representation on its own. (e.g. primitive cube)
    Definition: ge_prepass.h:947
    Note
    One can check with GeGetVersionType() and GeGetCinemaInfo() the version of the host Cinema 4D application to make sure plugins are only loaded in a suitable environment.
    Currently the return value of PluginStart() is not evaluated.

    PluginMessage

    PluginMessage() receives various messages during startup, shutdown and while Cinema 4D is running.

    It is possible to send a custom message to PluginMessage() of all loaded plugins with:

    Bool PluginMessage(Int32 id, void* data)
    {
    switch (id)
    {
    //...
    }
    return false;
    }
    Bool PluginMessage(Int32 id, void *data)
    maxon::Int32 Int32
    Definition: ge_sys_math.h:56

    Priority

    The PluginStart() and PluginEnd() functions of all plugins are called one after another. The plugin priority defines the order in which these functions are called. This is useful to make sure that a given plugin is called before or after a certain other plugin. For most plugins this is typically not needed.

    The priority is set using this macro:

    {
    return true;
    }
    #define SetPluginPriority(data, i)
    Definition: c4d_plugin.h:198
    #define C4DPL_INIT_PRIORITY_XTENSIONS
    Base priority for extensions.
    Definition: c4d_plugin.h:46
    #define C4DMSG_PRIORITY
    Called to query plugins about their loading time priority. Answer with SetPluginPriority(),...
    Definition: c4d_plugin.h:38

    The priorities are:

    Note
    Higher priorities are initialized first.
    C4DMSG_PRIORITY is not relevant for Python plugins.

    Initialize Resources

    If a plugin uses any resource files in its "res" folder, these resources have to be loaded when Cinema 4D starts. This is done using GeResource::Init().

    As this is one of the earliest message, this is the best time to register custom data types and SNHook plugins. This message is not sent to Python plugins.

    // This example loads the plugin's resources when
    // C4DPL_INIT_SYS is sent to PluginMessage().
    {
    // don't start plugin without resource
    if (g_resource.Init() == false)
    return false;
    return true;
    }
    GeResource g_resource
    Global resources for Cinema 4D.
    Bool Init()
    #define C4DPL_INIT_SYS
    Initialize system.
    Definition: c4d_plugin.h:28

    After the C4DPL_INIT_SYS message, PluginStart() will be called.

    Start

    During startup the following messages are sent:

    // This example inserts a cube object into the active scene after Cinema has started.
    {
    if (doc != nullptr)
    {
    if (cube == nullptr)
    return false;
    doc->InsertObject(cube, nullptr, nullptr);
    }
    return true;
    break;
    }
    BaseDocument * GetActiveDocument()
    Definition: c4d_basedocument.h:497
    Definition: c4d_baseobject.h:248
    static BaseObject * Alloc(Int32 type)
    #define C4DPL_PROGRAM_STARTED
    Sent when the application has been started.
    Definition: c4d_plugin.h:118
    #define Ocube
    Cube.
    Definition: ge_prepass.h:1119
    const char * doc
    Definition: pyerrors.h:226

    Menu Layout

    Before Cinema 4D finishes its start (C4DPL_PROGRAM_STARTED) it is possible to modify its menus to add new menu entries.

    // This example adds a new "Custom Menu" entry to Cinema's menu bar.
    {
    BaseContainer* const mainMenu = GetMenuResource("M_EDITOR"_s);
    if (mainMenu == nullptr)
    return false;
    // create a custom menu entry
    menu.InsData(MENURESOURCE_SUBTITLE, "Custom Menu");
    // adds the command to create a cube to the custom menu
    const String commandString = "PLUGIN_CMD_" + String::IntToString(Ocube);
    menu.InsData(MENURESOURCE_COMMAND, commandString);
    // add new menu entry
    mainMenu->InsData(MENURESOURCE_SUBMENU, menu);
    return true;
    break;
    }
    BaseContainer * GetMenuResource(const maxon::String &menuname)
    Definition: c4d_basecontainer.h:48
    GeData * InsData(Int32 id, const GeData &n)
    Definition: c4d_basecontainer.h:258
    Definition: c4d_string.h:41
    static String IntToString(Int32 v)
    Definition: c4d_string.h:497
    #define C4DPL_BUILDMENU
    Use GetMenuResource() etc. to add menus here if necessary. See main.cpp in the SDK examples.
    Definition: c4d_plugin.h:39
    @ MENURESOURCE_COMMAND
    Command, e.g. "IDM_NEU" or "PLUGIN_CMD_1000472".
    Definition: gui.h:242
    @ MENURESOURCE_SUBMENU
    BaseContainer Sub-menu:
    Definition: gui.h:240
    @ MENURESOURCE_SUBTITLE
    The title of the menu item or sub-menu.
    Definition: gui.h:243

    Command Line Arguments

    Warning
    Command line arguments can be defined and accessed with MAXON API configuration variables. See Configuration Variables.

    The command line arguments used to start Cinema 4D can be parsed after the application has started.

    The data of the message is C4DPL_CommandLineArgs:

    // This example catches the command line argument "-custom"
    // It must look like this: "-custom someString"
    {
    const C4DPL_CommandLineArgs* const args = static_cast<C4DPL_CommandLineArgs*>(data);
    if (args == nullptr)
    return false;
    // loop through all command line arguments
    for (Int32 i = 0; i < args->argc; i++)
    {
    // check if argument is set
    if (!args->argv[i])
    continue;
    // check if this is the "custom" argument
    if (strcmp(args->argv[i], "-custom") == 0)
    {
    // set to nullptr so it won't confuse other modules
    args->argv[i] = nullptr;
    // get the argument that is the next command line element
    i++;
    const String argument = String(args->argv[i]);
    // print result
    ApplicationOutput("Argument: " + argument);
    // set to nullptr so it won't confuse other modules
    args->argv[i] = nullptr;
    }
    }
    return true;
    break;
    }
    Py_ssize_t i
    Definition: abstract.h:645
    PyObject * args
    Definition: abstract.h:159
    #define argument
    Definition: graminit.h:83
    #define C4DPL_COMMANDLINEARGS
    Sent to let plugins parse the command line arguments used when starting Cinema&#160;4D....
    Definition: c4d_plugin.h:68
    #define ApplicationOutput(formatString,...)
    Definition: debugdiagnostics.h:204
    Definition: c4d_plugin.h:81

    Device Change

    When a device is added to or removed from the machine, a plugin message is sent.

    The data of the message is C4DPL_DeviceChange:

    // This example detects when a new device is added.
    {
    const C4DPL_DeviceChange* const dc = static_cast<C4DPL_DeviceChange*>(data);
    if (dc == nullptr)
    return false;
    const String* const name = dc->name;
    if (name == nullptr)
    return false;
    // check if name is valid
    if (name->GetLength() > 0)
    {
    // check if the device was removed or added
    if (dc->eject)
    ApplicationOutput("Device " + *name + " was removed");
    else
    ApplicationOutput("Device " + *name + " was added");
    }
    return true;
    break;
    }
    const char const char * name
    Definition: abstract.h:195
    #define C4DPL_DEVICECHANGE
    Sent when a device has changed. The data pointer should be cast to C4DPL_DeviceChange.
    Definition: c4d_plugin.h:104
    Definition: c4d_plugin.h:107
    class String * name
    The name of the device.
    Definition: c4d_plugin.h:108
    Bool eject
    true if the device was ejected, otherwise false.
    Definition: c4d_plugin.h:109
    Note
    This message is triggered twice per event.

    Shutdown

    The following messages are sent during Cinema 4D's shutdown.

    • C4DPL_ENDPROGRAM: Cinema 4D is about to close.
    • C4DPL_ENDACTIVITY is sent before PluginEnd() of any plugin is called. This allows to free any resources and close threads. At this point, all classes and plugins still exist. For example dialogs, BaseContainers, threads and complex data types should be deleted here. Preferences should be stored and all processes be terminated.
    • C4DPL_SHUTDOWNTHREADS: Sent to all plugins before the threading system of Cinema 4D is shut down. Afterwards no threads should be started.

    PluginEnd

    PluginEnd() is called before a plugin is unloaded and is the last opportunity to free resources. Here low level cleanup should be done e.g. for Strings and Filenames. Also imported DLLs should be unloaded here.

    void PluginEnd(void)
    {
    // Free resources
    }
    void PluginEnd()

    Further Reading