Archicad C++ API
About Archicad add-on development using the C++ API.

Store additional information for an element

Anonymous
Not applicable
Hi,

Which is the best way to concatenate information related to an element? Is it required to create an stl container and use that to store elements and related information, or is it possible to store arrays, variables, etc inside the elements?

Thanks: Andor
9 REPLIES 9
Anonymous
Not applicable
Any short example how to properly use SetUserData and GetUserData?

Thanks.
Tibor Lorantfy
Graphisoft Alumni
Graphisoft Alumni
Hi Andor,

I wrote you a short example how to use ACAPI_Element_GetUserData/SetUserData.
// Create an own structure which contains all the necessary informations what you want to store in element's user data 
typedef struct { 
	Int32 myNumbers[5]; 
	char myInfo[API_InfoLen]; 
} MyElementUserData; 
 
// ----------------------------------------------------------------------------- 
bool SetElementUserData (const API_Guid& guid, const API_ElemTypeID& typeID) // Add extra parameters if needed 
{ 
	API_ElementUserData	userData; 
	MyElementUserData**	myUserData = NULL; 
	API_Elem_Head		elemHead; 
	GSErrCode			err = NoError; 
 
	BNZeroMemory (&userData, sizeof (API_ElementUserData)); 
	userData.dataVersion  = 1; 
	userData.platformSign = GS::Act_Platform_Sign; 
	// Set flags if you need: 
	//  userData.flags = APIUserDataFlag_FillWith | APIUserDataFlag_Pickup | APIUserDataFlag_UndoAble | APIUserDataFlag_SkipRecalcAndDraw; 
	userData.dataHdl = BMAllocateHandle (sizeof (MyElementUserData), ALLOCATE_CLEAR, 0); 
	if (userData.dataHdl == NULL) 
		return false; 
 
	myUserData = (MyElementUserData**) (userData.dataHdl); 
	// Fill the allocated userdata as you want: 
	for (Int32 ii = 0; ii < 5; ++ii) { 
		(*myUserData)->myNumbers[ii] = ii + 1; 
	} 
	sprintf ((*myUserData)->myInfo, "My Info!"); 
 
	// Attach userdata to the element: 
	BNZeroMemory (&elemHead, sizeof (API_Elem_Head)); 
	elemHead.guid = guid; 
	elemHead.typeID = typeID; 
	err = ACAPI_Element_SetUserData (&elemHead, &userData); 
	if (userData.dataHdl != NULL) 
		BMKillHandle (&userData.dataHdl); 
 
	return err == NoError ? true : false; 
} 
 
// ----------------------------------------------------------------------------- 
bool GetElementUserData (const API_Guid& guid, const API_ElemTypeID& typeID, MyElementUserData** myUserData) 
{ 
	API_ElementUserData	userData; 
	API_Elem_Head		elemHead; 
	GSErrCode			err = NoError; 
 
	BNZeroMemory (&userData, sizeof (API_ElementUserData)); 
 
	// Get userdata from the element: 
	BNZeroMemory (&elemHead, sizeof (API_Elem_Head)); 
	elemHead.guid = guid; 
	elemHead.typeID = typeID; 
	err = ACAPI_Element_GetUserData (&elemHead, &userData); 
	if (err != NoError || userData.dataVersion != 1) { 
		if (userData.dataHdl != NULL) 
			BMKillHandle (&userData.dataHdl); 
		return false; 
	} 
 
	myUserData = (MyElementUserData**) (userData.dataHdl); 
	return true; 
} 
 
// ----------------------------------------------------------------------------- 
// Usage example: 
bool result = false; 
result = SetElementUserData (myGuid, myType); 
 
// ... 
 
MyElementUserData** myUserData = NULL; 
result = GetElementUserData (myGuid, myType, myUserData); 
 
if (result) { 
	// read the userdata 
	Int32 myFirstNumber = (*myUserData)->myNumbers[0]; 
	// ... 
} 
 
// Don't forget to release the handle after using! 
if (myUserData != NULL) 
	BMKillHandle ((GSHandle*) &myUserData);


Regards,
Tibor
Anonymous
Not applicable
Hi Tibor

Is the line "elemHead.typeID = typeID; " required in the example you posted, or is it redundant?

Thanks

Paul
Tibor Lorantfy
Graphisoft Alumni
Graphisoft Alumni
paulk wrote:
Is the line "elemHead.typeID = typeID; " required in the example you posted, or is it redundant?
Good question
Everywhere you can identify an element with only the GUID, you don't need the type+index pair anymore. So it's not required.
Anonymous
Not applicable
Everywhere you can identify an element with only the GUID, you don't need the type+index pair anymore. So it's not required.
Thank you.

Paul
Anonymous
Not applicable
Tibor - I have an issue where I am calling the code you posted above from:
case DG_MSG_CLICK:
			switch (itemId) {
				case 1: // Close Button	
					SetElementUserData(params);
					break;
However - the call to...
err = ACAPI_Element_SetUserData (&elemHead, &userData);
kills the ArchiCAD selection system. So after that call, I can select another ArchiCAD element, but I cannot then select the element the data was saved for in the 3d view (by mouseclicking the element), even with "Arrow" select. Selection of elements in 2d views is OK though. err is returning NoError. If I move the camera in the 3d view, other elements can be selected again. Rem'ing that line out fixes the problem (but doesn't save the data to the element). This is AC17 5005. This appears to be an ArchiCAD bug.

Paul
ReignBough
Enthusiast
Does element user data per add-on or can I access the same user data with different add-on?
~ReignBough~
ARCHICAD 26 INT (from AC18)
Windows 11 Pro, AMD Ryzen 7, 3.20GHz, 32.0GB RAM, 64-bit OS
Tibor Lorantfy
Graphisoft Alumni
Graphisoft Alumni
ReignBough wrote:
Does element user data per add-on or can I access the same user data with different add-on?


Each Add-On can attach own userdata to an element, but the attached userdata can be accessed only by the owner Add-On.
Akos Somorjai
Graphisoft
Graphisoft
Tibor wrote:
ReignBough wrote:
Does element user data per add-on or can I access the same user data with different add-on?


Each Add-On can attach own userdata to an element, but the attached userdata can be accessed only by the owner Add-On.
Additional info: this is for data safety reasons, we don't allow other add-ons to accidentally compromise the data of another add-on.

If you have several add-ons, you can still use add-on — add-on communication to query and set the user data.

Best, Akos