Custom GUID
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-09-27
04:03 PM
- last edited on
2022-10-06
01:04 PM
by
Daniel Kassai
Solved! Go to Solution.
- Labels:
-
Add-On (C++)
Accepted Solutions

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-10-02 07:17 PM
I wrote an example. In this way you can store any kind of data. Feel free to extend it:
#include "MemoryIChannel.hpp" #include "MemoryOChannel.hpp" #include "SetPlatformProtocol.hpp" class MyUserData { Int32 id; char string[128]; GSErrCode LoadFromUserData (const API_ElementUserData& userData); GSErrCode SaveToUserData (API_ElementUserData& userData) const; public: MyUserData () : id (-1) {} MyUserData (Int32 id, const char* cstr) : id (id) { CHTruncate (cstr, string, sizeof (string)); } GSErrCode GetFromElement (const API_Guid& elemGuid); GSErrCode SetToElement (const API_Guid& elemGuid) const; }; // ----------------------------------------------------------------------------- // How to set: MyUserData userData (1234, "My own ID"); userData.SetToElement (elemGuid); // How to get: MyUserData userData2; if (userData2.GetFromElement (elemGuid2) != APIERR_NOUSERDATA) { // } // ----------------------------------------------------------------------------- GSErrCode MyUserData::LoadFromUserData (const API_ElementUserData& userData) { IO::MemoryIChannel memChannel (*(userData.dataHdl), BMGetHandleSize (userData.dataHdl)); IO::SetPlatformIProtocol (memChannel, static_cast<GS::PlatformSign> (userData.platformSign)); GSErrCode err = NoError; err = memChannel.Read (id); if (err != NoError) return err; err = memChannel.Read (string); if (err != NoError) return err; return NoError; } GSErrCode MyUserData::SaveToUserData (API_ElementUserData& userData) const { userData.dataVersion = 1; userData.platformSign = GS::Act_Platform_Sign; userData.flags = APIUserDataFlag_FillWith | APIUserDataFlag_Pickup; IO::MemoryOChannel memChannel; memChannel.Write (id); memChannel.Write (string); const USize nBytes = memChannel.GetDataSize (); const char* pData = memChannel.GetDestination (); userData.dataHdl = BMAllocateHandle (nBytes, ALLOCATE_CLEAR, 0); if (userData.dataHdl == nullptr) return APIERR_MEMFULL; BNCopyMemory (*(userData.dataHdl), pData, nBytes); return NoError; } GSErrCode MyUserData::GetFromElement (const API_Guid& elemGuid) { API_ElementUserData userData = {}; API_Elem_Head elemHead = {}; elemHead.guid = elemGuid; GSErrCode err = ACAPI_Element_GetUserData (&elemHead, &userData); if (err != NoError) return err; err = LoadFromUserData (userData); BMKillHandle (&userData.dataHdl); return err; } GSErrCode MyUserData::SetToElement (const API_Guid& elemGuid) const { API_ElementUserData userData = {}; GSErrCode err = SaveToUserData (userData); if (err != NoError) return err; API_Elem_Head elemHead = {}; elemHead.guid = elemGuid; err = ACAPI_Element_SetUserData (&elemHead, &userData); BMKillHandle (&userData.dataHdl); return err; }

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-09-27 04:55 PM
What's your purpose? Why do you need an element with your specific own GUID?
You can set custom 'Element ID' string to the elements. That could be also a good way to identify your own elements.
Or you can set custom userdata for the elements using ACAPI_Element_SetUserData function.
Or you can create your own property definition and set that property to any custom value/string for the elements.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-09-27 05:44 PM

I'm trying to create external database. And some operations can't be updated with modify function so I'm deleting elements and createing new ones. Of course then I get different guids in files and database...

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-09-28 10:35 AM
However, I got the only Version and when I read value I got 0 or a bunch of integers. So I assume either I didn't assign value and It's 0 from allocation or in another case I'm saving pointer instead of value.
There is only one difference with an example in BMPtrAndHandle second parameter is a pointer, not value. The function didn't accept the dereferenced value.
int savedData = 234; int* savedDataPtr = &savedData; int** sDataPtrPtr = &savedDataPtr; API_AttributeUserData MyUserData; userData.dataVersion = 1234; userData.platformSign = GS::Win_Platform_Sign; userData.dataHdl = BMAllocateHandle(sizeof(int), ALLOCATE_CLEAR,0); GSErr ud_err = BMPtrAndHandle(&sDataPtrPtr, userData.dataHdl, sizeof(int)); GS::ErrCode err = ACAPI_Attribute_SetUserData(&attr.header, &userData);
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-10-02 05:09 PM


- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-10-02 07:17 PM
I wrote an example. In this way you can store any kind of data. Feel free to extend it:
#include "MemoryIChannel.hpp" #include "MemoryOChannel.hpp" #include "SetPlatformProtocol.hpp" class MyUserData { Int32 id; char string[128]; GSErrCode LoadFromUserData (const API_ElementUserData& userData); GSErrCode SaveToUserData (API_ElementUserData& userData) const; public: MyUserData () : id (-1) {} MyUserData (Int32 id, const char* cstr) : id (id) { CHTruncate (cstr, string, sizeof (string)); } GSErrCode GetFromElement (const API_Guid& elemGuid); GSErrCode SetToElement (const API_Guid& elemGuid) const; }; // ----------------------------------------------------------------------------- // How to set: MyUserData userData (1234, "My own ID"); userData.SetToElement (elemGuid); // How to get: MyUserData userData2; if (userData2.GetFromElement (elemGuid2) != APIERR_NOUSERDATA) { // } // ----------------------------------------------------------------------------- GSErrCode MyUserData::LoadFromUserData (const API_ElementUserData& userData) { IO::MemoryIChannel memChannel (*(userData.dataHdl), BMGetHandleSize (userData.dataHdl)); IO::SetPlatformIProtocol (memChannel, static_cast<GS::PlatformSign> (userData.platformSign)); GSErrCode err = NoError; err = memChannel.Read (id); if (err != NoError) return err; err = memChannel.Read (string); if (err != NoError) return err; return NoError; } GSErrCode MyUserData::SaveToUserData (API_ElementUserData& userData) const { userData.dataVersion = 1; userData.platformSign = GS::Act_Platform_Sign; userData.flags = APIUserDataFlag_FillWith | APIUserDataFlag_Pickup; IO::MemoryOChannel memChannel; memChannel.Write (id); memChannel.Write (string); const USize nBytes = memChannel.GetDataSize (); const char* pData = memChannel.GetDestination (); userData.dataHdl = BMAllocateHandle (nBytes, ALLOCATE_CLEAR, 0); if (userData.dataHdl == nullptr) return APIERR_MEMFULL; BNCopyMemory (*(userData.dataHdl), pData, nBytes); return NoError; } GSErrCode MyUserData::GetFromElement (const API_Guid& elemGuid) { API_ElementUserData userData = {}; API_Elem_Head elemHead = {}; elemHead.guid = elemGuid; GSErrCode err = ACAPI_Element_GetUserData (&elemHead, &userData); if (err != NoError) return err; err = LoadFromUserData (userData); BMKillHandle (&userData.dataHdl); return err; } GSErrCode MyUserData::SetToElement (const API_Guid& elemGuid) const { API_ElementUserData userData = {}; GSErrCode err = SaveToUserData (userData); if (err != NoError) return err; API_Elem_Head elemHead = {}; elemHead.guid = elemGuid; err = ACAPI_Element_SetUserData (&elemHead, &userData); BMKillHandle (&userData.dataHdl); return err; }
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-10-02 10:30 PM
You are a life saver. I will test it right away!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-10-07 04:01 PM
I was recently wondering why the whole API is not structured as classes?? But with structs and all methods as separate functions. It would be much easier to have API_Element as a class with all parameters and methods warped up in one class. I'm actually doing in spare time but it would be great to have it ready made by professional developers. Since there is always some conversion confusion and memory issues to consider.
Anyway is there any reason or benefit of using such kind of coding style?
GS::ErrCode MyUserData::SetToAttrib(const API_Attribute& attrib) const { API_AttributeUserData userData = {}; GSErrCode err = SaveToUserDataAtt(userData); if (err != NoError) return err; API_Attr_Head attHead = {}; attHead.index = attrib.header.index; attHead.typeID = attrib.header.typeID; err = ACAPI_Attribute_SetUserData(&attHead, &userData); BMKillHandle(&userData.dataHdl); return err; }
GS::ErrCode MyUserData::GetFromAttribute(const API_Attribute& attrib) { API_AttributeUserData userData = {}; API_Attr_Head attHead = {}; attHead.index = attrib.header.index; attHead.typeID = attrib.header.typeID; GSErrCode err = ACAPI_Attribute_GetUserData(&attHead, &userData); if (err != NoError) return err; err = LoadFromUserDataAtt(userData); BMKillHandle(&userData.dataHdl); return err; }

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-10-07 05:02 PM
kzaremba wrote:Nice, I'm glad you succeed!
It's working perfectly. I added Attributes as well there is a slight adjustment since ACAPI_Attribute_Set_UserData takes only type and Idx instead of GUID. So I'm passing API_Attribute instead of GUID.
kzaremba wrote:It has historical reasons. The first ARCHICAD version was released more than 30 years ago and the first API version is also more than 20 years old. Back then C++ was still just a baby...
I was recently wondering why the whole API is not structured as classes?? But with structs and all methods as separate functions. It would be much easier to have API_Element as a class with all parameters and methods warped up in one class.
You're absolutely right, it would be much more easier that way, but ARCHICAD database is a very complex system.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-10-08 08:14 PM
Tibor wrote:Thx to you
Nice, I'm glad you succeed!

Tibor wrote:So if it's only historical... Do you think there is a possibility to start GitRepository (or similar solution) to create the library of classes working with actual API (like the example above)? So if someone is interested in developing such an approach could collaborate and build upon some examples like this? This might be an even better way to share this knowledge than the forum where some topics are covered by the others.
it would be much more easier that way