cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 
Archicad C++ API
About Archicad add-on development using the C++ API.

Changing the Library folder in ARCHICAD12

Anonymous
Not applicable
Hi,

I want to change my project Libraries Folder in ArchiCAD 12.
I am using following function.

Void setupLibrariesForAC12()
{
API_LibrariesInfo libInfo;

memset(&libInfo, 0, sizeof(API_LibrariesInfo));
libInfo.nLib = 2;
libInfo.locations = (IO::Location**) BMAllocateHandle (libInfo.nLib * sizeof(IO::Location, ALLOCATE_CLEAR, 0);
libInfo.useSatellite = false;

new (*libInfo.locations) IO::Location (“C:\\Archicad12\\Archicad Library”);
new (*libInfo.locations + 1) IO::Location (“C:\\Archicad Development Library”);

ACAPI_Environment(APIEnv_SetLibrariesID, &libInfo, NULL);
(*libInfo.locations).~Location();
(*libInfo.locations + 1).~Location();

BMKillHandle(reinterpret_cast<GSHandle *> (&libInfo.locations));
}

But I am getting following errors
err LNK2001:unresolved external symbol “public: virtual class GS::ClassInfo * __thiscall GS::Object::GetClassInfoA(void)const “(?getClassInfoA@object@GS@@UBEPAVClassInfo@2@XZ)
fatal error LNK1120: 1 unresolved externals.

Please help me to solve these errors.
23 REPLIES 23
Oleg
Expert
The Location class may allocate some heap memory internally.
Destructor call is necessary to release it by Location.
I dont think the placement new is the reason.
A handle is not typed array, like std::vecor or C++ array and destructor will not called automatically.

Oleg
Ranga wrote:
I want to change my project Libraries Folder in ArchiCAD 12. I am using following function.
Void setupLibrariesForAC12()
{ etc...
Just for clarity, this function could be:
void setupLibrariesForAC12()
{ 
	API_LibrariesInfo libInfo; 
	
	memset(&libInfo, 0, sizeof(API_LibrariesInfo)); 
	libInfo.nLib = 2; 
	libInfo.locations = (IO::Location**) BMAllocateHandle (libInfo.nLib * sizeof(IO::Location, ALLOCATE_CLEAR, 0)); 
	libInfo.useSatellite = false; 
	
	(*libInfo.locations)[0] = IO::Location(“C:\\Archicad12\\Archicad Library”); 
	(*libInfo.locations)[1] = IO::Location(“C:\\Archicad Development Library”); 
	
	ACAPI_Environment(APIEnv_SetLibrariesID, &libInfo, NULL); 
	
	BMKillHandle(reinterpret_cast<GSHandle *> (&libInfo.locations)); 
} 
Could someone from GS comment on whether the calls to placement new and the Location destructor are necessary for some internal initialisation or cleanup?

Ranga, are you sure the link error is connected to this function, i.e. did it link properly previously? And have you linked to the correct libraries as Oleg suggested?
Ralph Wessel BArch
Central Innovation
Oleg wrote:
The Location class may allocate some heap memory internally.
Destructor call is necessary to release it by Location.
I dont think the placement new is the reason.
A handle is not typed array, like std::vecor or C++ array and destructor will not called automatically.
Yes, the Location object may have allocated resources... or may do so in future - perhaps it's also a safeguard against future changes?
Ralph Wessel BArch
Central Innovation
Oleg
Expert
Ralph wrote:
Yes, the Location object may have allocated resources... or may do so in future - perhaps it's also a safeguard against future changes?
Yes, it may have as dynamically length of string path.
But may it is just POD members so your right and desrtuctor is not necessary.

Better if GS do special function like
KillLocationHandle as there is for Prams etc.

But more clear design if there will not mix C++ and C (as most struct is plain structs).
Lets Location returns raw data state and has constructor from state.
Location loc("tt");
LocationState s = loc.GetState();
Lovation l2(s);

And Handle will be og LocationState.

Or move to C++ and break untyped Handles.

But I agree with Ralph, this puzzled direct destructor call is strange.
Oleg wrote:
Better if GS do special function like
KillLocationHandle as there is for Prams etc.
But more clear design if there will not mix C++ and C (as most struct is plain structs).
I agree - this is messy. I guess AC (like most mature software) has to get by with some awkward scenarios as the new is built onto the old. I've sent an email asking for clarification on this one.

Thinking about it, you are probably right. The Location object might either allocate resources or rely on reference counting to release resources when no object refers to them. Either way, explicitly releasing the object would be essential.
Ralph Wessel BArch
Central Innovation
Akos Somorjai
Graphisoft
Graphisoft
Ralph wrote:
I agree - this is messy. I guess AC (like most mature software) has to get by with some awkward scenarios as the new is built onto the old. I've sent an email asking for clarification on this one.

Thinking about it, you are probably right. The Location object might either allocate resources or rely on reference counting to release resources when no object refers to them. Either way, explicitly releasing the object would be essential.
Yep, it does contain a few pointers, which have to be allocated correctly with a constructor call, and also does registration and un-registration as well.
So, all in all, as Oleg said, the BM... routines didn't handle C++ classes correctly, so in some version of the API we have to get rid of them, and use C++-safe containers like GS::Array<>.
In this special case the placement new and the placement delete are required because we store the instance of the C++ class in the non-typed handle, which of course doesn't call the destructor and the constructor.
Anonymous
Not applicable
Ralph wrote:
Ranga wrote:
I want to change my project Libraries Folder in ArchiCAD 12. I am using following function.
Void setupLibrariesForAC12()
{ etc...
Just for clarity, this function could be:
void setupLibrariesForAC12()
{ 
	API_LibrariesInfo libInfo; 
	
	memset(&libInfo, 0, sizeof(API_LibrariesInfo)); 
	libInfo.nLib = 2; 
	libInfo.locations = (IO::Location**) BMAllocateHandle (libInfo.nLib * sizeof(IO::Location, ALLOCATE_CLEAR, 0)); 
	libInfo.useSatellite = false; 
	
	(*libInfo.locations)[0] = IO::Location(“C:\\Archicad12\\Archicad Library”); 
	(*libInfo.locations)[1] = IO::Location(“C:\\Archicad Development Library”); 
	
	ACAPI_Environment(APIEnv_SetLibrariesID, &libInfo, NULL); 
	
	BMKillHandle(reinterpret_cast<GSHandle *> (&libInfo.locations)); 
} 
Could someone from GS comment on whether the calls to placement new and the Location destructor are necessary for some internal initialisation or cleanup?

Ranga, are you sure the link error is connected to this function, i.e. did it link properly previously? And have you linked to the correct libraries as Oleg suggested?
hi Ralph,

If I am using destructor I am getting Link error and If I am not using destructor No errors and and my code working fine(it setting new library).

Ranga
Ranga wrote:
If I am using destructor I am getting Link error and If I am not using destructor No errors and and my code working fine(it setting new library).
Based on the comments from Ákos, you really do need to use placement new and the destructor. Although the amount of memory leaked will probably be quite small, it's poor practice and might bite you later.

I've compiled and linked a project using this function without problems, so I think your project is missing a library. I'm not sure which one is required in this case - I'm linking against the following in XCode:
  • VBUtils.framework
    VBAttributes.framework
    UC.framework
    TextEngine.framework
    ProjectFile.framework
    PixMapIO.framework
    ObjectDatabase.framework
    ModelerGraphics.framework
    libACAP_STAT.a
    JACK.framework
    InputOutput.framework
    GX.framework
    GSZLib.framework
    GSXMLUtils.framework
    GSXML.framework
    GSUtils.framework
    GSRoot.framework
    GSQuickTime.framework
    GSModeler.framework
    Geometry.framework
    GDL.framework
    DG.framework
    AttributeManager.framework
Ralph Wessel BArch
Central Innovation
Anonymous
Not applicable
Hi!
I've the same linker error:
error LNK2001: unresolved external symbol "public: virtual class GS::ClassInfo * __thiscall GS::Object::GetClassInfoW(void)const " (?GetClassInfoW@Object@GS@@UBEPAVClassInfo@2@XZ)
after that as added following code
GS::Array<GS::ArrayFB<GS::UniString, 3>> autotexts;
This is a peace of sample from API Development Kit help
The "APIAny_GetAutoTextsID" topic
Example:
#include "UniString.hpp"
#include "Array.hpp"

GS::Array<GS::ArrayFB<GS::UniString, 3> > autotexts;
API_AutotextType type = APIAutoText_Fixed;

GSErrCode err = ACAPI_Goodies (APIAny_GetAutoTextsID, &autotexts, (void *) (long) type);
if (err == NoError) {
for (ULong i = 0; i < autotexts.GetSize (); i++) {
DBPrintf ("AutoText[%03d] \"%s\" (\"%s\") = \"%s\"\n", i,
(const char *) autotexts[0].ToCStr (), (const char *) autotexts[1].ToCStr (), (const char *) autotexts[2].ToCStr ());
}
}

Here is list of my libs:

acap_stat.lib
libcmtd.lib
LIBCPMTD.LIB
kernel32.lib
advapi32.lib
user32.lib
GSRootImp.lib
dgimp.lib
InputOutputImp.lib
libxml2.lib
iconv.lib

I tried include others libs that have GetClassInfo symbol, but it did not help.
Hope to your help!

Thanks in advance,
AT
Anonymous
Not applicable
Hi Apis Terrestris,

May be try this way, it may works.

API_librariesInfo libInfo;
OSErr err;

memset(&libInfo, 0, sizeof(API_librariesInfo));
err = ACAPI_Environment(API_Env_GetLibrariedId, &libInfo, NULL);
if(err == noErr)
{
for(int ii = 0; ii < libInfo.nLib; ++ii)
{
DBPrintf ("AutoText[%03d] = \"%s\"\n", i, GetCPathFromLocation(&(*libInfo.locations)[ii]));
}
}

char * GetCpathFromLocation(IO::Location* location)
{
static char static_path[MAX_Path];
IO::Path path;

if(location->ToPath(&path) == noErr)
strcpy(static_path, path);
else
static_path[0] = ‘\0’;
return static_path;
}

I will try differently with example ‘APIAny_GetAutoTextsID’ and if it works for me I will get back to 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!