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

How export API_LibPart GSM on computer

LVirone Greisch
Booster

Hello,

 

I successfully create a GSM object in Archicad Library, but I don't find a way to export it (or directly create it) on my computer.

 

Currently, I set the API_LibPart.location in the embeddedLibrary. I tried to set the location on a computer folder and it doesn't work (I get an error -2130312314), I suppose I need to create it in Archicad before exporting it, am I correct?

Virone Lorenzo
1 ACCEPTED SOLUTION

Accepted Solutions
Solution

Hi,

 

I found a solution from the LibPart_Test:

 

GS::Array<API_LibraryInfo> libInfo;
ACAPI_LibraryManagement_GetLibraries(&libInfo);

IO::Location folderLoc;

/*API_SpecFolderID specID = API_UserDocumentsFolderID;
ACAPI_ProjectSettings_GetSpecFolder(&specID, &folderLoc);*/

folderLoc = *(new IO::Location());
folderLoc.Set(GS::UniString("D:\\"));

folderLoc.AppendToLocal(IO::Name("LibPart_Test Library"));
IO::Folder destFolder(folderLoc, IO::Folder::Create);

libPart.location = new IO::Location(folderLoc);

bool vari = true;
for (UInt32 ii = 0; ii < libInfo.GetSize(); ii++) {
if (folderLoc == libInfo[ii].location)
vari = false;
}

if(vari)
{
API_LibraryInfo li;
li.location = folderLoc;

libInfo.Push(li);

ACAPI_LibraryManagement_SetLibraries(&libInfo);
}

const GS::UnID unID = BL::BuiltInLibraryMainGuidContainer::GetInstance().GetUnIDWithNullRevGuid(BL::BuiltInLibPartID::ModelElementLibPartID);

CHCopyC(unID.ToUniString().ToCStr(), libPart.parentUnID); // Model Element subtype

GSTimeRecord timeRecord;
TIGetTimeRecord(0, &timeRecord, TI_CURRENT_TIME);
UInt32 fraction = TIGetTicks() % TIGetTicksPerSec();
GS::snuprintf(libPart.docu_UName, sizeof(libPart.docu_UName) / sizeof(GS::uchar_t), L("LPTest_%d-%02d-%02d_%02d%02d%02d_%d"),
timeRecord.year, timeRecord.month, timeRecord.day, timeRecord.hour, timeRecord.minute, timeRecord.second, fraction);



ACAPI_LibraryPart_Create(&libPart);

//Create the libPart here, like in the code in my previous message on this thread

ACAPI_LibraryPart_Save(&libPart);

 

I suspect the problem come from using GS::ucscpy instead of GS::snuprintf, or maybe using API_LibraryInfo to set the library created.

 

But it works so I'm happy with it ! I get a GSM file at "D:\LibPart_Test Library".

 

Thanks again for your help @Oleg

Virone Lorenzo

View solution in original post

8 REPLIES 8
Oleg
Expert

I dont understood your issue exactly, so just a reply about the error code.

See ErrorCodes page of API documentation.
Error -2130312314 means APIERR_NESTING "The API function is not reentrant. Nesting occurred."

I think it is not location issue.

Hello and thanks for the reply.

 

I've the error -2130313215 the first time I execute my code, then -2130312314 all the next time in the same Archicad instance.

 

The base of my code come from Speckle connector for Archicad, their methods GetLocation() and CreateSubFolder() work fine to create a library part in the embedded library, it failed when I try to set a Windows path. Source code: https://github.com/specklesystems/speckle-archicad/blob/release/3.0.0/AddOns/Speckle/Sources/AddOn/C...

 

The code I tried:

 

API_LibPart libPart;
BNClear(libPart);
BNZeroMemory(&libPart, sizeof(API_LibPart));
libPart.typeID = APILib_ObjectID;
libPart.isTemplate = false;
libPart.isPlaceable = true;

//Location part
IO::Location* loc = new IO::Location();
loc->Set(GS::UniString("D:\\Test")); //The path I want
libPart.location = loc;

CHCopyC("{57B7C584-5C0D-11D6-A0D8-036F034B6791}-{00000000-0000-0000-0000-000000000000}", libPart.parentUnID); // General Stair subtype
GS::ucscpy(libPart.docu_UName, L("Test LibPart")); //library part name

ACAPI_LibraryPart_Create(&libPart); //This method return the error
Virone Lorenzo
Oleg
Expert

Hi

Is this all your code for test ?

PS: 
LibPart creation is a building process, starts by ACAPI_LibraryPart_Create and ends by ACAPI_LibraryPart_Save.
LibPart's sections are created between them.
Like in Sparcle's LibpartBuilder::CreateLibPart method.

Oleg
Expert

Tried the your code above. 
But added ACAPI_LibraryPart_Save to avoid -2130312314 error.  
It works for me (although it wasn't AC28).

If I change drive letter to non-existent on my PC, I got -2130313215 error.
May be you dont have "D" drive.


Hello and thank you,

 

I have the D on my computer, and yes my full code is longer. For now I'm testing to create a simple box with a custom parameter.

 

Everything works when I create it in the embedded library, but when I try to set the path I always got the "-2130313215" error at "ACAPI_LibraryPart_Save(&libPart);". 

 

I created a folder "C:\Test" on my computer.

 

Note I have the error "-2130312310" when tried with path "C://", I suppose I cannot write directly on C.

 

My full code :

---------------------------------------------------

void CreateGSM()
{
API_LibPart libPart;
BNClear(libPart);
BNZeroMemory(&libPart, sizeof(API_LibPart));
libPart.typeID = APILib_ObjectID;
libPart.isTemplate = false;
libPart.isPlaceable = true;
IO::Location* loc = new IO::Location();
loc->Set(GS::UniString("C:\\Test")); //or "C:\\Test\\"
libPart.location = loc;
CHCopyC("{57B7C584-5C0D-11D6-A0D8-036F034B6791}-{00000000-0000-0000-0000-000000000000}", libPart.parentUnID); // General Stair subtype
GS::ucscpy(libPart.docu_UName, L("Test LibPart"));
CHECK_ERROR(ACAPI_LibraryPart_Create(&libPart));
API_LibPartSection section;
GS::String line;

// Copyright section
BNZeroMemory(&section, sizeof(API_LibPartSection));
section.sectType = API_SectCopyright;
CHECK_ERROR(ACAPI_LibraryPart_NewSection(&section));
line = "Test Author"; // Author
CHECK_ERROR(ACAPI_LibraryPart_WriteSection(line.GetLength(), line.ToCStr()));
CHECK_ERROR(ACAPI_LibraryPart_EndSection());

// 3D script section
BNZeroMemory(&section, sizeof(API_LibPartSection));
section.sectType = API_Sect3DScript;
CHECK_ERROR(ACAPI_LibraryPart_NewSection(&section));
line = "block 1,1,1";
CHECK_ERROR(ACAPI_LibraryPart_WriteSection(line.GetLength(), line.ToCStr()));
CHECK_ERROR(ACAPI_LibraryPart_EndSection());

// Parameter script section
BNZeroMemory(&section, sizeof(API_LibPartSection));
section.sectType = API_SectVLScript;
ACAPI_LibraryPart_NewSection(&section);
ACAPI_LibraryPart_EndSection();

//Parameters script
BNZeroMemory(&section, sizeof(API_LibPartSection));
section.sectType = API_SectParamDef;
short nPars = 2;
API_AddParType** addPars = reinterpret_cast<API_AddParType**>(BMAllocateHandle(nPars * sizeof(API_AddParType), ALLOCATE_CLEAR, 0));
if (addPars != nullptr)
{
API_AddParType* pAddPar = &(*addPars)[0];
pAddPar->typeID = APIParT_RealNum;
pAddPar->typeMod = 0;
CHTruncate("SklTestParameter", pAddPar->name, sizeof(pAddPar->name));
GS::ucscpy(pAddPar->uDescname, L("Test Parameter"));
pAddPar->value.real = 1;
double aa = 1.0;
double bb = 1.0;
GSHandle sectionHdl = nullptr;
ACAPI_LibraryPart_GetSect_ParamDef(&libPart, addPars, &aa, &bb, nullptr, &sectionHdl);
API_LibPartDetails details;
BNZeroMemory(&details, sizeof(API_LibPartDetails));
details.object.autoHotspot = false;
details.object.fixSize = true;
ACAPI_LibraryPart_SetDetails_ParamDef(&libPart, sectionHdl, &details);
ACAPI_LibraryPart_AddSection(&section, sectionHdl, nullptr);
BMKillHandle(reinterpret_cast<GSHandle*>(&addPars));
BMKillHandle(&sectionHdl);
}
else
{
ACAPI_WriteReport("Failed to allocate memory for LibPart parameter.", true);
return;
}

// Save the constructed library part
CHECK_ERROR(ACAPI_LibraryPart_Save(&libPart));
}

---------------------------------------------------

 

 

In a different .h file:

---------------------------------------------------

#pragma once
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#ifndef CHECK_ERROR
#define CHECK_ERROR(f)\
{\
GSErrCode err = (f);\
if (err != NoError)\
{\
GS::UniString message = "Error in: " + GS::UniString(TOSTRING(f)) + ", Code: " + GS::ValueToUniString(err); \
ACAPI_WriteReport(message, true);\
}\
}
#endif

---------------------------------------------------

 

Thank you

Virone Lorenzo
Oleg
Expert

I dont know a reason, sorry.

Just a last guess.

May be you run the test on demo archicad and may be the ACAPI_LibraryPart_Save has limitation.


Ok no problem, no I'm not on demo because I was afraid of the same thing, I have a full licence and my AddOn has a valid MDID.

 

Maybe its just obsolete in Archicad 28.4001 ? There is this message in the Documentation : Legacy function - to be deleted in future versions, use ACAPI::LM::GSMObject setters instead        https://graphisoft.github.io/archicad-api-devkit/group___library_part.html#ga9d6ed5258ccb9669ce890e7...

 

I'll try again and send the result here if I found something.

Thanks again for all your answers.

Virone Lorenzo
Solution

Hi,

 

I found a solution from the LibPart_Test:

 

GS::Array<API_LibraryInfo> libInfo;
ACAPI_LibraryManagement_GetLibraries(&libInfo);

IO::Location folderLoc;

/*API_SpecFolderID specID = API_UserDocumentsFolderID;
ACAPI_ProjectSettings_GetSpecFolder(&specID, &folderLoc);*/

folderLoc = *(new IO::Location());
folderLoc.Set(GS::UniString("D:\\"));

folderLoc.AppendToLocal(IO::Name("LibPart_Test Library"));
IO::Folder destFolder(folderLoc, IO::Folder::Create);

libPart.location = new IO::Location(folderLoc);

bool vari = true;
for (UInt32 ii = 0; ii < libInfo.GetSize(); ii++) {
if (folderLoc == libInfo[ii].location)
vari = false;
}

if(vari)
{
API_LibraryInfo li;
li.location = folderLoc;

libInfo.Push(li);

ACAPI_LibraryManagement_SetLibraries(&libInfo);
}

const GS::UnID unID = BL::BuiltInLibraryMainGuidContainer::GetInstance().GetUnIDWithNullRevGuid(BL::BuiltInLibPartID::ModelElementLibPartID);

CHCopyC(unID.ToUniString().ToCStr(), libPart.parentUnID); // Model Element subtype

GSTimeRecord timeRecord;
TIGetTimeRecord(0, &timeRecord, TI_CURRENT_TIME);
UInt32 fraction = TIGetTicks() % TIGetTicksPerSec();
GS::snuprintf(libPart.docu_UName, sizeof(libPart.docu_UName) / sizeof(GS::uchar_t), L("LPTest_%d-%02d-%02d_%02d%02d%02d_%d"),
timeRecord.year, timeRecord.month, timeRecord.day, timeRecord.hour, timeRecord.minute, timeRecord.second, fraction);



ACAPI_LibraryPart_Create(&libPart);

//Create the libPart here, like in the code in my previous message on this thread

ACAPI_LibraryPart_Save(&libPart);

 

I suspect the problem come from using GS::ucscpy instead of GS::snuprintf, or maybe using API_LibraryInfo to set the library created.

 

But it works so I'm happy with it ! I get a GSM file at "D:\LibPart_Test Library".

 

Thanks again for your help @Oleg

Virone Lorenzo

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!