In continuation from the disussion concerning ToolData container, I am encountering an issue I cannot seem to put my finger on. So I extracted the offending code into a separate dummy plugin.
The whole code is below.
A command data when executed will parse the Live Selection
description and store all settings into a basecontainer, which is located in a separate class.
When Cinema 4D is then closed the class hosting the basecontainer is destroyed, which calls the basecontainer's destructor, which will perform a FlushAll
.
For one reason or another this call crashes.
I have pinpointed the issue to the SplineData
which is part of the soft-selection settings of the Live Tool (while not actively shown this attribute is still part of the description).
This SplineData is a custom data type, and when I omit copying this attribute into the test basecontainer all goes well when class is destroyed.
To me, it seems as if copying the data into the container does not make a copy, but uses the original pointer. Hence, when the test class and its test basecontainer is destroyed it will try to destroy the SplineData ... which has already been destroyed as a result of Cinema 4D closing (... at least, that's my guess).
If I store the settings into a basecontainer of the command data then there seem to be no problem.
Which does make me think I am doing something wrong with my test class allocation/deallocation.
I just cannot seem to see what exactly it is I am doing wrong.
Tried with R16, R17, ...
// ========================
// Testing
// Dummy "empty" plugin
// ========================
#include "c4d.h"
// Dummy IDs - for demonstration purposes only
#define MYCOMMAND_PLUGIN_ID 1999999
class Test
{
public:
Test() {}
virtual ~Test() {}
BaseContainer mTestContainer;
};
Test* gTest = nullptr;
// ====================================
// CommandData
// ====================================
class MyCommand : public CommandData
{
INSTANCEOF(MyCommand, CommandData)
public:
virtual Bool Execute(BaseDocument* doc);
virtual Bool ExecuteSubID(BaseDocument* doc, Int32 subid);
virtual Int32 GetState(BaseDocument* doc);
virtual Bool RestoreLayout(void* secret);
virtual Bool Message(Int32 type, void* data);
// BaseContainer mToolData;
};
Bool MyCommand::Execute(BaseDocument* doc)
{
// get the live selection description
const Int32 id = ID_MODELING_LIVESELECTION;
BasePlugin* plug = FindPlugin(id, PLUGINTYPE_TOOL); // needs explicitely to be PLUGINTYPE_TOOL, as PLUGINTYPE_ANY does not work correctly
if (!plug)
return FALSE;
AutoAlloc<Description> desc;
if (desc && plug->GetDescription(desc, DESCFLAGS_DESC_0))
{
void *handle = desc->BrowseInit();
DescID dcid, groupid;
GeData gd;
const BaseContainer *objBc = NULL;
while (desc->GetNext(handle, &objBc, dcid, groupid))
{
if (objBc) {
const String name = objBc->GetString(DESC_NAME);
const Int32 id = dcid[0].id;
plug->GetParameter(DescID(dcid), gd, DESCFLAGS_GET_0);
const Int32 type = gd.GetType();
// attributes can be buttons, bars, ...
// anything without a user input value, skip these
if (type == DA_NIL)
continue;
//mToolData.SetData(id, gd);
gTest->mTestContainer.SetData(id, gd);
}
}
desc->BrowseFree(handle); //Free the memory used by the Browse function
}
return TRUE;
}
Bool MyCommand::ExecuteSubID(BaseDocument* doc, Int32 subid)
{
return TRUE;
}
Int32 MyCommand::GetState(BaseDocument* doc)
{
return CMD_ENABLED;
}
Bool MyCommand::RestoreLayout(void* secret)
{
return TRUE;
}
Bool MyCommand::Message(Int32 type, void* data)
{
return SUPER::Message(type, data);
}
Bool RegisterMyCommand(void)
{
return RegisterCommandPlugin(MYCOMMAND_PLUGIN_ID, "Testing", 0, AutoBitmap("icon.png"), "Test", NewObjClear(MyCommand));
}
// ====================================
// Plugin Main
// ====================================
Bool PluginStart(void)
{
RegisterMyCommand();
gTest = NewObjClear(Test);
if (!gTest)
return FALSE;
return TRUE;
}
void PluginEnd(void)
{
if (gTest)
{
gTest->mTestContainer.FlushAll(); // This line was added for testing out the flushing -> it crashes ... why?
// without the above line, the destructor of the Test class would call BaseContainer's destructor, which would perform a FlushAll -> this crashes
DeleteObj(gTest);
}
}
Bool PluginMessage(Int32 id, void * data)
{
switch (id) {
case C4DPL_INIT_SYS:
if (!resource.Init())
return FALSE;
return TRUE;
case C4DMSG_PRIORITY:
return TRUE;
case C4DPL_BUILDMENU:
break;
case C4DPL_ENDACTIVITY:
return TRUE;
}
return FALSE;
}