A BaseContainer is a collection of individual values. Each value has its own ID and type. A BaseContainer can also carry any number of child containers. 90% of Cinema 4D's internal values are stored in containers and all messages are working with containers, so this class is an essential part of the SDK. Containers can store any GeData type, including custom data types. It is recommended to use the available containers to store values in custom NodeData based plugins.

Keep in mind that there is no guarantee for a value to be in the container. Use default values whenever possible when accessing container's ID data.
Use the typed access methods (for example BaseContainer::GetBool()) whenever possible, instead of the low-level BaseContainer::GetData(). See Access.
Once a container value has been set using one type one must neither try to access it using another type, nor overwrite it with a value of another type. Using the wrong access will not crash, but it is illegal.
To browse through all elements of a BaseContainer use the class BrowseContainer.


Every BaseList2D based object of the Cinema 4D API has a BaseContainer that stores its data. This BaseContainer can be accessed with:

See BaseList2D Manual.

Object parameters should be edited with C4DAtom::GetParameter() / C4DAtom::SetParameter(). Not all parameters of an object may be stored in the BaseContainer.
// This example accesses the BaseContainer storing the render settings.
// The BaseContainer is needed as an argument of RenderDocument().
RenderData* const rdata = doc->GetActiveRenderData();
if (rdata == nullptr)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
const BaseContainer renderSettings = rdata->GetData();
if (bitmap == nullptr)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
// prepare target bitmap
const Int32 width = renderSettings.GetInt32(RDATA_XRES, 1280);
const Int32 height = renderSettings.GetInt32(RDATA_YRES, 720);
const IMAGERESULT imageRes = bitmap->Init(width, height);
if (imageRes != IMAGERESULT::OK)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
// render the image
const RENDERRESULT res = RenderDocument(doc, renderSettings, nullptr, nullptr, bitmap, flags, nullptr);
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
// show the result in the Picture Viewer
PyCompilerFlags * flags
Definition: ast.h:14
RENDERRESULT RenderDocument(BaseDocument *doc, const BaseContainer &rdata, ProgressHook *prog, void *private_data, BaseBitmap *bmp, RENDERFLAGS renderflags, BaseThread *th, WriteProgressHook *wprog=nullptr, void *data=nullptr)
Bool ShowBitmap(const Filename &fn)
Definition: ge_autoptr.h:37
Definition: c4d_basecontainer.h:47
Int32 GetInt32(Int32 id, Int32 preset=0) const
Definition: c4d_basecontainer.h:303
BaseContainer GetData()
Definition: c4d_baselist.h:2309
Definition: c4d_basedocument.h:144
Py_UCS4 * res
Definition: unicodeobject.h:1113
Definition: drendersettings.h:153
Definition: drendersettings.h:154
maxon::Int32 Int32
Definition: ge_sys_math.h:60
Definition: ge_prepass.h:3896
@ OK
Image loaded/created.
Definition: ge_prepass.h:4663
Set to avoid an automatic clone of the scene sent to RenderDocument().
Definition: ge_prepass.h:419
@ OK
Function was successful.
Definition: memoryallocationbase.h:67
unsigned long Py_ssize_t width
Definition: pycore_traceback.h:88
const char * doc
Definition: pyerrors.h:226

BaseContainer elements are also often used as an argument in a function call.


The complete content of a BaseContainer object can be copied to another object:

It is also possible to copy a BaseContainer using the copy constructor.

// This example creates a BaseContainer copies in different ways:
BaseContainer original;
original.SetString(100, "foo"_s);
original.SetString(200, "bar"_s);
// CopyTo()
BaseContainer target;
target.SetString(300, "foobar"_s);
if (!original.CopyTo(&target, COPYFLAGS::NONE, nullptr))
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
ApplicationOutput(target.GetString(300)); // This value is now deleted.
// GetClone()
BaseContainer* clone = original.GetClone(COPYFLAGS::NONE, nullptr);
if (clone == nullptr)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
// Copy Constructor
BaseContainer copy(original);
// Assignment
BaseContainer assignment = original;
Bool CopyTo(BaseContainer *dst, COPYFLAGS flags, AliasTrans *trans) const
Definition: c4d_basecontainer.h:110
String GetString(Int32 id, const maxon::String &preset=maxon::String()) const
Definition: c4d_basecontainer.h:387
void SetString(Int32 id, const maxon::String &s)
Definition: c4d_basecontainer.h:569
BaseContainer * GetClone(COPYFLAGS flags, AliasTrans *trans) const
Definition: c4d_basecontainer.h:101
#define ApplicationOutput(formatString,...)
Definition: debugdiagnostics.h:210
#define DeleteObj(obj)
Definition: newobj.h:159
To merge containers see BaseContainer::MergeContainer() in chapter Functionality.



A BaseContainer can have an ID. This ID can be used to identify the container.

// This example shows how GetId() is used to identify the message sent to GeDialog::Message().
switch (msg.GetId())
// interaction start; if the value is changed create an undo
_interactStart = true;
// interaction end, if an undo was created, end it
if (_undoStarted)
_undoStarted = false;
_interactStart = false;
return SUPER::Message(msg, result);
BaseDocument * GetActiveDocument(void)
Definition: c4d_basedocument.h:498
PyObject PyObject * result
Definition: abstract.h:43
Definition: gui.h:916
Sent when user interaction ends.
Definition: gui.h:935
const char const char * msg
Definition: object.h:438


A BaseContainer stores its data using GeData objects. It is possible to access these GeData objects or the stored values directly using typed access functions. It is recommended to prefer the typed access functions.

A copy of a GeData element can be obtained with:

The DescLevel::id property is used as the actual ID.
// This example stores some data in
// the BaseContainer using SetParameter().
bc.SetParameter(DescID { 100 }, GeData { "foobar" });
GeData data;
bc.GetParameter(DescID { 100 }, data);
Bool SetParameter(const DescID &id, const GeData &t_data)
Definition: c4d_basecontainer.h:635
Bool GetParameter(const DescID &id, GeData &t_data) const
Definition: c4d_basecontainer.h:628
Definition: lib_description.h:330
Definition: c4d_gedata.h:83
const String & GetString(void) const
Definition: c4d_gedata.h:463

The GeData elements are also accessible via:

// This example stores some data in the
// BaseContainer using a GeData object.
bc.SetData(100, GeData { "foobar" });
GeData data = bc.GetData(100);
const GeData & GetData(Int32 id) const
Definition: c4d_basecontainer.h:262
GeData * SetData(Int32 id, const GeData &n)
Definition: c4d_basecontainer.h:255

For fast access read-only pointers to the GeData elements are accessible:

// This example accesses the data stored
// in the BaseContainer using data pointers.
bc.SetData(100, GeData { "foo" });
bc.SetData(200, GeData { "bar" });
const Int count = 2;
const GeData* data[count];
Int32 ids[] = { 100, 200 };
bc.GetDataPointers(ids, count, data);
if (data[0])
if (data[1])
Py_ssize_t count
Definition: abstract.h:640
void GetDataPointers(const Int32 *ids, Int32 cnt, const GeData **data) const
Definition: c4d_basecontainer.h:217
maxon::Int Int
Definition: ge_sys_math.h:64

A GeData element is also accessible via its index in the BaseContainer:

// This example accesses the data stored in the
// BaseContainer using the element index.
bc.SetData(100, GeData { "foo" });
bc.SetData(200, GeData { "bar" });
GeData* const first = bc.GetIndexData(0);
if (first != nullptr)
GeData* const second = bc.GetIndexData(1);
if (second != nullptr)
GeData * GetIndexData(Int32 index) const
Definition: c4d_basecontainer.h:229

New GeData elements can be added to the BaseContainer:

// This example inserts some data into the
// BaseContainer after the first element.
bc.SetData(100, "foo");
bc.SetData(200, "foobar");
GeData* const data = bc.GetIndexData(0);
bc.InsDataAfter(150, String("bar"), data);
GeData * InsDataAfter(Int32 id, const GeData &n, GeData *last)
Definition: c4d_basecontainer.h:247
Definition: c4d_string.h:39

To access the values of primitive data types, these access functions are available:

See also Primitive Data Types Manual (Classic).

A BaseContainer can store a void pointer.

This should not be used to store a reference to a C4DAtom based element; instead a BaseLink should be used.
// This example stores a void pointer
// in the BaseContainer object.
bc.SetVoid(100, &object);
// ...
SomeObject* const obj = static_cast<SomeObject*>(bc.GetVoid(100));
void SetVoid(Int32 id, void *v)
Definition: c4d_basecontainer.h:540
void * GetVoid(Int32 id, void *preset=nullptr) const
Definition: c4d_basecontainer.h:343
PyObject * obj
Definition: complexobject.h:60

A BaseContainer can store raw memory:

// This example stores a BaseArray as raw memory. (in that case an array of Vectors)
// Calculates the size of the memory
maxon::Int size = myArray.GetCount() * SIZEOF(maxon::Vector);
if (size == 0)
bc.SetMemory(uniqueID, nullptr, 0);
// Retrieves the memory pointer using Disconnect. (so the memory will not be freed twice)
void* pArray = myArray.Disconnect().Begin().GetPtr();
if (pArray == nullptr)
return maxon::UnknownError(MAXON_SOURCE_LOCATION);
// Sets the memory in the BaseContainer
bc.SetMemory(uniqueID, pArray, size);
void SetMemory(Int32 id, void *mem, Int count)
Definition: c4d_basecontainer.h:548
Py_ssize_t size
Definition: bytesobject.h:86
Int64 Int
signed 32/64 bit int, size depends on the platform
Definition: apibase.h:190
#define SIZEOF(x)
Calculates the size of a datatype or element.
Definition: apibasemath.h:205
// This Example reads a BaseArray stored as raw memory.
// Creates an array
// Creates a block to retrieves the memory from the block.
// Retrieves the memory, use GetMemoryAndRelease to release the pointer or the memory will be freed twice)
void* memFromContainer = bc.GetMemoryAndRelease((Int32)uniqueID, size);
if (memFromContainer != nullptr && size > 0)
// Calculates the number of elements for vectors
maxon::Vector* myMem = static_cast<maxon::Vector*>(memFromContainer);
if (myMem == nullptr)
return maxon::NullptrError(MAXON_SOURCE_LOCATION);
// Fills the block with the memory.
myblock.Set(myMem, size);
// Connects the array with the block.
myOtherArray.Connect(myblock, size);
// Prints the value of the array.
for (auto& value : myOtherArray)
ApplicationOutput("Value is @", value);
PyObject * value
Definition: abstract.h:715
void * GetMemoryAndRelease(Int32 id, Int &count, void *preset=nullptr)
Definition: c4d_basecontainer.h:354
Definition: basearray.h:412
MAXON_ATTRIBUTE_FORCE_INLINE void Connect(const Block< T > &block, Int capacity=0)
Definition: basearray.h:1722
Definition: block.h:423
void Set(T *ptr, Int size, Int stride=(STRIDED &&GENERIC) ? -1 :SIZEOF(StrideType))
Definition: block.h:550

A BaseContainer offers also access functions for mathematical data types:

See also Vector Manual (Classic) and Matrix Manual (Classic).

A BaseContainer offers further access functions for typical Cinema 4D data types:

See also String Manual (Classic) and Filename Manual.

See also BaseTime Manual.

A BaseContainer also offers special functions to store and handle BaseLink objects:

See also BaseLink Manual.

// store the current selection in the BaseContainer
bc.SetLink(100, doc->GetActiveMaterial());
bc.SetLink(200, doc->GetActiveObject());
bc.SetLink(300, doc->GetActiveTag());
// ...
// get the material
BaseMaterial* const mat = bc.GetMaterialLink(100, doc);
if (mat)
// get the object
BaseObject* const obj = bc.GetObjectLink(200, doc);
if (obj)
// get tag
BaseList2D* const link = bc.GetLink(300, doc);
if (link)
BaseObject * GetObjectLink(Int32 id, const BaseDocument *doc) const
BaseMaterial * GetMaterialLink(Int32 id, const BaseDocument *doc) const
BaseList2D * GetLink(Int32 id, const BaseDocument *doc, Int32 instanceof=0) const
Definition: c4d_basecontainer.h:443
void SetLink(Int32 id, C4DAtomGoal *link)
Definition: c4d_basecontainer.h:604
Definition: c4d_baselist.h:2188
String GetName() const
Definition: c4d_baselist.h:2361
Definition: c4d_basematerial.h:28
Definition: c4d_baseobject.h:225

A BaseContainer object can also store further sub-containers:

// This example stores a sub-container
// in the BaseContainer object.
BaseContainer subcontainer;
subcontainer.SetString(100, "foobar"_s);
bc.SetContainer(100, subcontainer);
// ...
BaseContainer sub = bc.GetContainer(100);
void SetContainer(Int32 id, const BaseContainer &s)
Definition: c4d_basecontainer.h:597
BaseContainer GetContainer(Int32 id) const
Definition: c4d_basecontainer.h:418

A BaseContainer can also store custom data types. To set the value of the custom data type a GeData object is needed.

// This example gets the current time and saves is as DateTimeData in the BaseContainer.
// Then the DateTimeData is received from that BaseContainer.
DateTime time;
if (date == nullptr)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
GeData data;
bc.SetData(100, data);
// ...
const CustomDataType* const customData = bc.GetCustomDataType(100, DATETIME_DATA);
const DateTimeData* const dateTimeData = static_cast<const DateTimeData*>(customData);
if (dateTimeData)
const DateTime dt = dateTimeData->GetDateTime();
result += String::IntToString(dt.day) + " - ";
// print output
const CustomDataType * GetCustomDataType(Int32 id, Int32 datatype) const
Definition: customgui_datetime.h:157
void SetCustomDataType(Int32 datatype, const CustomDataType &v)
Definition: c4d_gedata.h:664
static String IntToString(Int32 v)
Definition: c4d_string.h:495
DateTime custom data ID.
Definition: customgui_datetime.h:23
void GetDateTimeNow(DateTime &t)
Int32 minute
Definition: customgui_datetime.h:67
Int32 day
Day in month.
Definition: customgui_datetime.h:64
Int32 month
Definition: customgui_datetime.h:63
Int32 second
Definition: customgui_datetime.h:68
Int32 year
Definition: customgui_datetime.h:62
DateTime GetDateTime() const
Int32 hour
Definition: customgui_datetime.h:66
Base class for custom data types.
Definition: c4d_customdatatype.h:51
Represents a date and time.
Definition: customgui_datetime.h:39

These functions can be used to limit the values of a Vector or Float value inside a BaseContaier:

These functions simply apply ClampValue(), see also Mathematical Functions Manual (Classic).


The elements stored within a BaseContainer are accessible through their index and their ID:

See also BaseContainer::GetIndexData() above. To loop through values see also BrowseContainer.

// This example loops through the values of the BaseContainer.
Int32 i = 0;
while (true)
const Int32 id = bc.GetIndexId(i++);
if (id == NOTOK)
Py_ssize_t i
Definition: abstract.h:645
Int32 GetIndexId(Int32 index) const
Definition: c4d_basecontainer.h:197
#define NOTOK
Definition: ge_sys_math.h:267


Elements can be removed from a BaseContainer:

// This example removes some element from
// the BaseContainer object.
bc.SetData(100, "foo");
bc.SetData(200, "bar");
// remove data entry 100
if (bc.RemoveData(100))
GeData data = bc.GetData(100);
// check if data has no type (data is not set)
if (data.GetType() == DA_NIL)
ApplicationOutput("Data removed"_s);
Bool RemoveData(Int32 id)
Definition: c4d_basecontainer.h:160
Int32 GetType(void) const
Definition: c4d_gedata.h:407
No value.
Definition: c4d_gedata.h:38


Several operations can be performed on a BaseContainer object.

// This example merges the content of two
// BaseContainer objects.
bc.SetData(100, "foo");
bc.SetData(200, "bar");
bc2.SetData(100, "100");
bc2.SetData(300, "300");
// this will result in the values
// 100: "100"
// 200: "bar"
// 300: "300"
void MergeContainer(const BaseContainer &src)


Two BaseContainer are identical if they have the same ID, the same number of entries and if the entries are also identical and in the same order.

Detect Changes

The dirty state of a BaseContainer changes incrementally when a value stored in the BaseContainer is changed.

// This example checks the dirty state after a value was added and changed.
bc.SetData(100, "foo");
UInt32 dirty = bc.GetDirty();
ApplicationOutput("Dirty State: " + String::UIntToString(dirty));
bc.SetData(100, "bar");
dirty = bc.GetDirty();
ApplicationOutput("Dirty State: " + String::UIntToString(dirty));
UInt32 GetDirty() const
Definition: c4d_basecontainer.h:148
static String UIntToString(UInt32 v)
Definition: c4d_string.h:511
maxon::UInt32 UInt32
Definition: ge_sys_math.h:61


The BrowseContainer class can be used to browse through the values stored in a BaseContainer. See also Index.

// This example loops through all values of the given BaseContainer.
Int32 id;
GeData* dat = nullptr;
// init BrowseContainer
BrowseContainer browse(&bc);
// loop through the values
while (browse.GetNext(&id, &dat))
// check if the current data stores a String
if (dat != nullptr)
if (dat->GetType() == DA_STRING)
ApplicationOutput("value: " + dat->GetString());
Definition: c4d_gedata.h:674
Definition: c4d_gedata.h:47

Disc I/O

A BaseContainer can be stored in a HyperFile.

// This example stores a BaseContainer in a HyperFile on disc.
if (hf == nullptr)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
// open HyperFile to write
return maxon::IoError(MAXON_SOURCE_LOCATION, MaxonConvert(filename, MAXONCONVERTMODE::NONE), "Could not open file."_s);
PyCompilerFlags const char * filename
Definition: ast.h:15
maxon::Url MaxonConvert(const Filename &fn, MAXONCONVERTMODE convertMode)
No check if file exists under case-sensitive drives.
Show an error dialog for any error.
// This example reads a BaseContainer from a HyperFile on disc.
if (hf == nullptr)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
// open HyperFile to read
if (hf->Open(123, filename, FILEOPEN::READ, FILEDIALOG::ANY))
hf->ReadContainer(&bc, true);
Open the file for reading.

See also HyperFile Manual on BaseContainer.

Further Reading