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

The ModulData datastore type

Anonymous
Not applicable
How does ModulData store complex structures or classes
Hope someone can reply, thank you
4 REPLIES 4
Ralph Wessel
Mentor
That's up to you - ModulData simply stores the requested number of bytes of data. What you put there is up to you. We serialise objects as XML for storage.
Ralph Wessel BArch
Software Engineer Speckle Systems
Anonymous
Not applicable
Is MemoryOChannel the only way to apply for storage space?
I observed some code in the ModulData_Manager case in the API.

class CustomerData {
public:
	GS::Guid			guid;
	GS::UniString		name;
	GS::UniString		city;
	GS::UniString		country;
	double				aa;
	int					ii;
	bool				modified;
	bool				markedAsDeleted;

	CustomerData () : modified (false), markedAsDeleted (false) { }

	CustomerData (const API_ModulData& modulData, const GS::UniString& modulName) : modified (false), markedAsDeleted (false)
	{
		guid.ConvertFromString (modulName);
		if (modulData.dataHdl != nullptr && modulData.dataVersion == 1) {
			IO::MemoryIChannel memChannel (*modulData.dataHdl, BMGetHandleSize (modulData.dataHdl));
			if (modulData.platformSign != GS::Act_Platform_Sign) {
				GS::PlatformSign ps = (modulData.platformSign == GS::Win_Platform_Sign) ? GS::Win_Platform_Sign :
									  ((modulData.platformSign == GS::Mac_Platform_Sign) ? GS::Mac_Platform_Sign : GS::Mactel_Platform_Sign);
				IO::SetPlatformIProtocol (memChannel, ps);
			}
			Read (memChannel);
		}
	}

	GSErrCode	Read (GS::IChannel& ic)
	{
		name.Read (ic);
		city.Read (ic);
		country.Read (ic);
		
		return ic.GetInputStatus ();
	}

	GSErrCode	Write (GS::OChannel& oc) const
	{
		name.Write (oc);
		city.Write (oc);
		country.Write (oc);
		return oc.GetOutputStatus ();
	}

	void	GenerateRandomContent (void)
	{
		static const char firstNames[10][32] = { "Albert", "Alex", "Alfred", "Amy", "Andrew", "Angelina", "Anne", "Anthony", "Arnold", "Arthur" };
		static const char familyNames[10][32] = { "Smith", "Johnson", "Williams", "Brown", "Jones", "Miller", "Davis", "Garcia", "Rodriguez", "Wilson" };
		static const char cities[10][32] = { "San Francisco", "Budapest", "Amsterdam", "Venezia", "Helsinki", "Limassol", "Tokyo", "Barcelona", "Abuja", "Auckland" };
		static const char countries[10][32] = { "United States", "Hungary", "Netherlands", "Italy", "Finland", "Cyprus", "Japan", "Spain", "Nigeria", "New Zeeland" };

		Int32 firstNameIndex = rand () % 10;
		Int32 familyNameIndex = rand () % 10;
		Int32 locationIndex = rand () % 10;
		name = GS::UniString (firstNames[firstNameIndex]) + " " + GS::UniString (familyNames[familyNameIndex]);
		city = GS::UniString (cities[locationIndex]);
		country = GS::UniString (countries[locationIndex]);
	}
};

static void ConvertModulesFromOldFormat (void)
{
	GS::Array<GS::UniString> modulNameList;
	ACAPI_ModulData_GetList (&modulNameList);

	for (GS::Array<GS::UniString>::ConstIterator it = modulNameList.Enumerate (); it != nullptr; ++it) {
		const GS::UniString& oldModulName = *it;
		API_ModulData oldModulData;
		BNZeroMemory (&oldModulData, sizeof (API_ModulData));
		if (ACAPI_ModulData_GetInfo (&oldModulData, oldModulName) == NoError) {
			if (oldModulData.dataVersion < 1) {						// old version (all customers stored in the same moduldata)
				if (ACAPI_ModulData_Get (&oldModulData, oldModulName) == NoError) {
					IO::MemoryIChannel oldModulMemChannel (*oldModulData.dataHdl, BMGetHandleSize (oldModulData.dataHdl));
					if (oldModulData.platformSign != GS::Act_Platform_Sign) {
						GS::PlatformSign ps = (oldModulData.platformSign == GS::Win_Platform_Sign) ? GS::Win_Platform_Sign :
											  ((oldModulData.platformSign == GS::Mac_Platform_Sign) ? GS::Mac_Platform_Sign : GS::Mactel_Platform_Sign);
						IO::SetPlatformIProtocol (oldModulMemChannel, ps);
					}
					USize nObjects = 0;
					oldModulMemChannel.Read (nObjects);
					for (USize i = 0; i < nObjects; i++) {
						CustomerData customerData;
						customerData.guid.Generate ();
						customerData.Read (oldModulMemChannel);

						API_ModulData modulData;
						BNZeroMemory (&modulData, sizeof (API_ModulData));
						modulData.dataVersion = 1;
						modulData.platformSign = GS::Act_Platform_Sign;
						IO::MemoryOChannel memChannel;
						if (customerData.Write (memChannel) == NoError) {
							BMPtrToHandle (memChannel.GetDestination (), &modulData.dataHdl, memChannel.GetDataSize ());
							ACAPI_ModulData_Store (&modulData, customerData.guid.ToUniString ());	// store converted
							BMKillHandle (&modulData.dataHdl);
						}
					}
				}
				BMKillHandle (&oldModulData.dataHdl);
				ACAPI_ModulData_Delete (oldModulName);												// delete old format
			}
		}
	}
}		// ConvertModulesFromOldFormat
This code uses the classes IChannel and OChannel to read and write to the class data.
If you want to store your data, whether you need to follow case way to deal with.
I don't quite understand this place, Please give me a hand, thank you very much.
Ralph Wessel
Mentor
Sorry, I can't tell you much about the API functionality for serialisation or buffering. We wrote classes for that long before it existed in the API and the documentation for this part of the API is thin.

At a basic level, take a look at the structure of API_ModulData. Your data is stored in API_ModulData .dataHdl, which is of type GSHandle. You can allocate the space for a handle using BMAllocateHandle. Once space is allocated, you can copy data into it.

Using memory buffer and serialisation classes takes a lot of the pain out of this process by providing a 'black box' that simply reads and writes objects while concealing the low-level data management.
Ralph Wessel BArch
Software Engineer Speckle Systems
Anonymous
Not applicable
Thank you very much. It helped me a lot. Thank you

Didn't find the answer?

Check other topics in this Forum

Back to Forum

Read the latest accepted solutions!

Accepted Solutions

Start a new conversation!