SOLVED GeDialog Failing To Open

Hello.

I am encountering a problem when I insert my object plugin into a scene in R26, save the document and then reopen the file. When I click the button to open the GeDialog Cinema immediately crashes on me.

I stripped down the code for my GeDialog to the bare minimum that was still similar to the examples in the sdk and the problem is still occurring.

#include "c4d_general.h"
#include "c4d.h"
#include "c4d_symbols.h"
#include "main.h"

#define ID_RUNDIALOG 1059364
enum Controls
{
	idSendMessageLinkObject = 1000,
	idLinkedObject,
	idGatherChildren,

	idOverallScrollGroup = 2000,
	idGroupToFlush,
	idControls,

	idLaunchDialogWindow = 1500,
	idBasicControlGroup,
};

class ObjDialog : public GeDialog
{
public:
	ObjDialog() {}
	virtual ~ObjDialog() {}
	virtual Bool CreateLayout();
	virtual Bool InitValues();
	virtual void DestroyWindow();
	virtual Bool Command(Int32 id, const BaseContainer& msg);
	virtual Int32 Message(const BaseContainer& msg, BaseContainer& result);
};


Bool ObjDialog::CreateLayout()
{
	Bool res = GeDialog::CreateLayout();

	SetTitle("Dialog Window"_s);

	ScrollGroupBegin(idOverallScrollGroup, BFH_SCALEFIT | BFV_SCALEFIT, SCROLLGROUP_VERT | SCROLLGROUP_HORIZ);
	{
		GroupBegin(idGroupToFlush, BFH_SCALEFIT | BFV_SCALEFIT, 1, 0, String(), 0);
		{
			GroupBegin(idControls, BFH_SCALEFIT | BFV_SCALEFIT, 5, 0, String(), 0);
			{
			}
			GroupEnd();
		}
		GroupEnd();
	}
	GroupEnd();

	return res;
}

Bool ObjDialog::InitValues()
{
	if (!GeDialog::InitValues())
		return false;
	return true;
}

void ObjDialog::DestroyWindow() {}

Bool ObjDialog::Command(Int32 id, const BaseContainer& msg)
{
	return true;
}


Int32 ObjDialog::Message(const BaseContainer& msg, BaseContainer& result)
{
	return GeDialog::Message(msg, result);
}


class RunDialog : public ObjectData
{
public:
	virtual Bool Init(GeListNode* node);

	virtual BaseObject* GetVirtualObjects(BaseObject* op, HierarchyHelp* hh);
	virtual Bool Message(GeListNode* node, Int32 type, void* t_data);
	virtual Bool GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags);

	static NodeData* Alloc() { return NewObjClear(RunDialog); }

	maxon::BaseArray<BaseObject*> objArrayToCheckForMatch;
private:
	ObjDialog dlg;
};


Bool RunDialog::GetDDescription(GeListNode *node, Description *description, DESCFLAGS_DESC &flags)
{
	BaseContainer *dataInstance;
	const DescID *singleid;
	if (!description->LoadDescription(node->GetType()))
	{
	}

	dataInstance = ((BaseList2D*)node)->GetDataInstance(); // Get the container for the tag
	if (!dataInstance)
		return FALSE;
	singleid = description->GetSingleDescID();
	DescID cid;


	DescID DescHelperControlGroup = DescLevel(idBasicControlGroup, DTYPE_GROUP, 0);
	if (!singleid || DescHelperControlGroup.IsPartOf(*singleid, NULL))
	{
		BaseContainer bc;
		bc = GetCustomDataTypeDefault(DTYPE_GROUP);
		bc.SetString(DESC_NAME, "Run Dialog"_s);
		bc.SetInt32(DESC_COLUMNS, 1);
		bc.SetInt32(DESC_DEFAULT, 1);
		bc.SetBool(DESC_SCALEH, TRUE);

		if (!description->SetParameter(DescHelperControlGroup, bc, DescLevel(ID_RUNDIALOG)))
			return TRUE;
	}


	cid = DescLevel(idLaunchDialogWindow, DTYPE_BUTTON, 0);
	if (!singleid || cid.IsPartOf(*singleid, NULL))  //  important to check for speedup c4d!
	{
		BaseContainer bc;
		bc = GetCustomDataTypeDefault(DTYPE_BUTTON);
		bc.SetInt32(DESC_CUSTOMGUI, CUSTOMGUI_BUTTON);
		bc.SetString(DESC_NAME, "Open Dialog"_s);
		if (!description->SetParameter(cid, bc, DescHelperControlGroup))
			return TRUE;
	}




	flags |= DESCFLAGS_DESC::LOADED;

	return TRUE;
}

Bool RunDialog::Init(GeListNode* node)
{
	return true;
}


Bool RunDialog::Message(GeListNode* node, Int32 type, void* t_data)
{
	if (type == MSG_DESCRIPTION_COMMAND)
	{
		DescriptionCommand *dc = (DescriptionCommand*)t_data;
		if (!dc)
			return TRUE;
		Int32 ID = Int32(dc->_descId[0].id);
		BaseDocument* doc = node->GetDocument();
		if (!doc)
			return TRUE;

		switch (ID)
		{
			// Problem occurs here
			case idLaunchDialogWindow:
			{
				if (dlg.IsOpen() == false)
					dlg.Open(DLG_TYPE::ASYNC, ID_RUNDIALOG, -1, -1, 300, 200, 0, OPENDIALOGFLAGS::IGNORELAYOUT);
				break;
			}
		}
	}

	return true;
}

BaseObject* RunDialog::GetVirtualObjects(BaseObject* op, HierarchyHelp* hh)
{
	BaseObject *nullReturn = BaseObject::Alloc(Onull);

	return nullReturn;
}

Bool RegisterRunDialog()
{

	return RegisterObjectPlugin(ID_RUNDIALOG, "Run Dialog"_s, OBJECT_GENERATOR | OBJECT_INPUT, RunDialog::Alloc, "ORunDialog"_s, AutoBitmap("atom.tif"_s), 0);
}

I've used this same code in R20 and R25 and haven't had a single issue with opening the GeDialog, I only started encountering the problem in R26.

Looking at the examples in the sdk that deal with GeDialogs they are all opened via a CommandData plugin and the GeDialog manual specifically mentions that GeDialog based windows are typically owned by a CommandData plugin.

Is it now a requirement to use a CommandData plugin to open a GeDialog?

Any help would be greatly appreciated.

John Terenece

hi,
I am not able to reproduce the issue. Are you compiling in debug or release mode?

Cheers
Manuel

Release mode.

hi, sorry i missed the fact it is mandatory to save the file and reopen it.

I was able to reproduce the issue. I need to ask ours devs the best way to fix this.

Cheers,
Manuel

The issue is happening because no dialog operation should be done from a thread. Loading the scene is now done asynchronously and the object creation is done in a thread. The GeDialog constructor will be called from a thread and fail.

My suggestion is to replace the GeDialog variable by a pointer and be sure that the allocation and the deletion is done in the mainthread.

Because the GeDialog was not initialised correctly, the CDIalog was not defined so the function dlg.IsOpen() was crashing.
For extra check, you can check CDialog against nullptr like so

CDialog* intern = dlg->Get();

I also change the TRUE to true. TRUE should be avoided.

#include "c4d_general.h"
#include "c4d.h"
#include "c4d_symbols.h"

#include "maxon/thread.h"

#define ID_RUNDIALOG 1059364
 

enum Controls
{
	idSendMessageLinkObject = 1000,
	idLinkedObject,
	idGatherChildren,

	idOverallScrollGroup = 2000,
	idGroupToFlush,
	idControls,

	idLaunchDialogWindow = 1500,
	idBasicControlGroup,
};

class ObjDialog : public GeDialog
{
public:
	virtual Bool CreateLayout();
	virtual Bool InitValues();
	virtual void DestroyWindow();
	virtual Bool Command(Int32 id, const BaseContainer& msg);
	virtual Int32 Message(const BaseContainer& msg, BaseContainer& result);
};


Bool ObjDialog::CreateLayout()
{
	Bool res = GeDialog::CreateLayout();
	SetTitle("Dialog Window"_s);
	ScrollGroupBegin(idOverallScrollGroup, BFH_SCALEFIT | BFV_SCALEFIT, SCROLLGROUP_VERT | SCROLLGROUP_HORIZ);
	{
		GroupBegin(idGroupToFlush, BFH_SCALEFIT | BFV_SCALEFIT, 1, 0, String(), 0);
		{
			GroupBegin(idControls, BFH_SCALEFIT | BFV_SCALEFIT, 5, 0, String(), 0);
			{
			}
			GroupEnd();
		}
		GroupEnd();
	}
	GroupEnd();

	return res;
}

Bool ObjDialog::InitValues()
{
	if (!GeDialog::InitValues())
		return false;
	return true;
}

void ObjDialog::DestroyWindow() {}

Bool ObjDialog::Command(Int32 id, const BaseContainer& msg)
{
	return true;
}


Int32 ObjDialog::Message(const BaseContainer& msg, BaseContainer& result)
{
	return GeDialog::Message(msg, result);
}




class RunDialog : public ObjectData
{
public:
	virtual Bool Init(GeListNode* node);

	virtual BaseObject* GetVirtualObjects(BaseObject* op, HierarchyHelp* hh);
	virtual Bool Message(GeListNode* node, Int32 type, void* t_data);
	virtual Bool GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags);

	static NodeData* Alloc() { return NewObjClear(RunDialog); }

	maxon::BaseArray<BaseObject*> objArrayToCheckForMatch;

	void Free(GeListNode* node) override;
private:
	ObjDialog *dlg = nullptr;


};

Bool RunDialog::Init(GeListNode* node)
{
	if (dlg == nullptr)
	{
		maxon::ExecuteOnMainThread([this]() 
			{
				dlg = NewObjClear(ObjDialog);
			});
	}
	
	return true;
}

void RunDialog::Free(GeListNode* node) 
{
	if (dlg)
	{
		maxon::ExecuteOnMainThread([this]()
			{
				DeleteObj(dlg);
				dlg = nullptr;
			});
	}
}

Bool RunDialog::GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags)
{
	BaseContainer* dataInstance;
	const DescID* singleid;
	if (!description->LoadDescription(node->GetType()))
	{
	}

	dataInstance = ((BaseList2D*)node)->GetDataInstance(); // Get the container for the tag
	if (!dataInstance)
		return FALSE;
	singleid = description->GetSingleDescID();
	DescID cid;


	DescID DescHelperControlGroup = DescLevel(idBasicControlGroup, DTYPE_GROUP, 0);
	if (!singleid || DescHelperControlGroup.IsPartOf(*singleid, NULL))
	{
		BaseContainer bc;
		bc = GetCustomDataTypeDefault(DTYPE_GROUP);
		bc.SetString(DESC_NAME, "Run Dialog"_s);
		bc.SetInt32(DESC_COLUMNS, 1);
		bc.SetInt32(DESC_DEFAULT, 1);
		bc.SetBool(DESC_SCALEH, true);

		if (!description->SetParameter(DescHelperControlGroup, bc, DescLevel(ID_RUNDIALOG)))
			return true;
	}


	cid = DescLevel(idLaunchDialogWindow, DTYPE_BUTTON, 0);
	if (!singleid || cid.IsPartOf(*singleid, NULL))  //  important to check for speedup c4d!
	{
		BaseContainer bc;
		bc = GetCustomDataTypeDefault(DTYPE_BUTTON);
		bc.SetInt32(DESC_CUSTOMGUI, CUSTOMGUI_BUTTON);
		bc.SetString(DESC_NAME, "Open Dialog"_s);
		if (!description->SetParameter(cid, bc, DescHelperControlGroup))
			return true;
	}




	flags |= DESCFLAGS_DESC::LOADED;

	return true;
}




Bool RunDialog::Message(GeListNode* node, Int32 type, void* t_data)
{
	if (type == MSG_DESCRIPTION_COMMAND)
	{
		DescriptionCommand* dc = (DescriptionCommand*)t_data;
		if (!dc)
			return true;
		Int32 ID = Int32(dc->_descId[0].id);
		BaseDocument* doc = node->GetDocument();
		if (!doc)
			return true;

		switch (ID)
		{
			// Problem occurs here
			case idLaunchDialogWindow:
			{
				if (dlg)
				{
					CDialog* intern = dlg->Get();
					if (intern)
					{
						if (dlg->IsOpen() == false)
							dlg->Open(DLG_TYPE::ASYNC, ID_RUNDIALOG, -1, -1, 300, 200, 0, OPENDIALOGFLAGS::IGNORELAYOUT);
					}
				}
				break;
			}
		}
	}

	return true;
}

BaseObject* RunDialog::GetVirtualObjects(BaseObject* op, HierarchyHelp* hh)
{
	BaseObject* nullReturn = BaseObject::Alloc(Onull);

	return nullReturn;
}
Bool RegisterRunDialog();
Bool RegisterRunDialog()
{

	return RegisterObjectPlugin(ID_RUNDIALOG, "Run Dialog"_s, OBJECT_GENERATOR | OBJECT_INPUT, RunDialog::Alloc, ""_s, AutoBitmap("atom.tif"_s), 0);
}

Cheers,
Manuel

Thanks for the response. This seems to have solved the problem.

John Terenece