License Delivery maintenance is expected to occur on Saturday, November 30, between 8 AM and 11 AM CET. This may cause a short 3-hours outage in which license-related tasks: license key upload, download, update, SSA validation, access to the license pool and Graphisoft ID authentication may not function properly. We apologize for any inconvenience.
Archicad C++ API
About Archicad add-on development using the C++ API.

Get list of external linked files

MudratDetector
Enthusiast

WIN 10 | AC24 | VS2017

 

I am writing an add-on to scan all links, inspect external file names, and capture instances where a .bpn file has been linked in or a file from another project folder has been linked in.  I am starting with something from the  ..\Examples\Database_Control folder.

 

In Database_Control.cpp there is:

 

// -----------------------------------------------------------------------------
// Dump info for drawing links in the current database
// -----------------------------------------------------------------------------

static void		Do_ListDrawingLinks ()
{
...

 

 

I have modified it slightly to change the DBPrintf() statements to be ACAPI_WriteReport() statements.  This function now reads:

 

static void	Do_ListDrawingLinks()
{
	GSErrCode	err = NoError;

	GS::IntPtr	store = 1;
	err = ACAPI_Database(APIDb_StoreViewSettingsID, (void *)store);
	if (err != NoError) {
		store = -1;
		err = NoError;
	}

	API_DatabaseInfo	currentDB;
	BNZeroMemory(&currentDB, sizeof(API_DatabaseInfo));
	ACAPI_Database(APIDb_GetCurrentDatabaseID, &currentDB);

	GS::Array<API_Guid>  drawingList;
	if (ACAPI_Element_GetElemList(API_DrawingID, &drawingList) != NoError) {
		ACAPI_WriteReport("Error in ACAPI_Element_GetElemList ().", true);
		return;
	}

	for (auto& guid : drawingList.AsConst()) {
		API_Element		elem = {};
		elem.header.guid = guid;

		err = ACAPI_Element_Get(&elem);
		char buffer[128];

		ACAPI_WriteReport(itoa(err, buffer, 10), true);
		if (err != NoError) {
			//DBPrintf("DatabaseControl :: Do_ListDrawingLinks :: Cannot get Drawing with GUID %s.\n", APIGuidToString(guid).ToCStr().Get());
			ACAPI_WriteReport(GS::UniString::Printf("DatabaseControl :: Do_ListDrawingLinks :: Cannot get Drawing with GUID %s.\n", APIGuidToString(guid).ToCStr().Get()), false);
			ACAPI_WriteReport("Error in ACAPI_Element_GetElemList ().", true);
			continue;
		}

		API_DrawingLinkInfo		drwLinkInfo;
		err = ACAPI_Database(APIDb_GetDrawingLinkID, (void*)(&(elem.header.guid)), &drwLinkInfo);
		ACAPI_WriteReport(itoa(err, buffer, 10), true);
		if (err != NoError) {
			DBPrintf("DatabaseControl :: Do_ListDrawingLinks :: Cannot get link information for Drawing with GUID %s.\n", APIGuidToString(guid).ToCStr().Get());
			ACAPI_WriteReport(GS::UniString::Printf("DatabaseControl :: Do_ListDrawingLinks :: Cannot get link information for Drawing with GUID %s.\n", APIGuidToString(guid).ToCStr().Get()), false);
			if (drwLinkInfo.linkPath != nullptr)
				delete drwLinkInfo.linkPath;
			if (drwLinkInfo.viewPath != nullptr)
				BMKillPtr(&(drwLinkInfo.viewPath));
			continue;
		}

		//DBPrintf("\tlink No. %ld :", elem.drawing.linkUId);
		ACAPI_WriteReport(GS::UniString::Printf("\tLink No. %ld :", elem.drawing.linkUId), false);
		if (drwLinkInfo.linkPath != nullptr) {
			//DBPrintf("\t%s", drwLinkInfo.linkPath->ToDisplayText().ToCStr().Get());
			ACAPI_WriteReport(GS::UniString::Printf("\t%s", drwLinkInfo.linkPath->ToDisplayText().ToCStr().Get()), false);
			delete drwLinkInfo.linkPath;
		}
		else
		{
			ACAPI_WriteReport("drwLinkInfo.linkPath == nullptr", false);
		}

		if (drwLinkInfo.viewPath != nullptr)
			BMKillPtr(&(drwLinkInfo.viewPath));

		if (drwLinkInfo.linkTypeID == API_DrawingLink_InternalViewID)
		{
			ACAPI_WriteReport("IS internal link type...", false);
			//DBPrintf("\t (internal %s, guid: %s)", (drwLinkInfo.viewType == API_ViewNodePerspective || drwLinkInfo.viewType == API_ViewNodeAxonometry) ? "3D view" : "view", APIGuidToString(drwLinkInfo.linkGuid).ToCStr().Get());
			ACAPI_WriteReport(GS::UniString::Printf("\t(0) (internal %s, guid: %s)", (drwLinkInfo.viewType == API_ViewNodePerspective || drwLinkInfo.viewType == API_ViewNodeAxonometry) ? "3D view" : "view", APIGuidToString(drwLinkInfo.linkGuid).ToCStr().Get()), false);
		}
		else
		{
			ACAPI_WriteReport("NOT internal link type...", false);
		}

		if (drwLinkInfo.linkTypeID == API_DrawingLink_ExternalViewID)
		{
			//DBPrintf("\t (internal %s, guid: %s)", (drwLinkInfo.viewType == API_ViewNodePerspective || drwLinkInfo.viewType == API_ViewNodeAxonometry) ? "3D view" : "view", APIGuidToString(drwLinkInfo.linkGuid).ToCStr().Get());
			ACAPI_WriteReport(GS::UniString::Printf("\t(1) (external %s, guid: %s)", (drwLinkInfo.viewType == API_ViewNodePerspective || drwLinkInfo.viewType == API_ViewNodeAxonometry) ? "3D view" : "view", APIGuidToString(drwLinkInfo.linkGuid).ToCStr().Get()), false);
		}
		else
		{
			ACAPI_WriteReport("NOT external link type...", false);
		}

		API_DatabaseInfo	dbInfo;
		BNZeroMemory(&dbInfo, sizeof(API_DatabaseInfo));
		dbInfo.typeID = APIWind_DrawingID;
		dbInfo.linkedElement = elem.header.guid;
		err = ACAPI_Database(APIDb_ChangeCurrentDatabaseID, &dbInfo);
		ACAPI_WriteReport(itoa(err, buffer, 10), true);
		if (err == NoError) {
			GS::Array<API_Guid> elemList;
			ACAPI_Element_GetElemList(API_LineID, &elemList);
			//DBPrintf("\t(number of lines = %ld,", elemList.GetSize());
			ACAPI_WriteReport(GS::UniString::Printf("\t(number of lines = %ld,", elemList.GetSize()), false);

			short	visible, onStory, inView;
			visible = onStory = inView = 0;
			for (auto& elemGuid : elemList.AsConst()) {
				if (ACAPI_Element_Filter(elemGuid, APIFilt_OnVisLayer))
					++visible;
				if (ACAPI_Element_Filter(elemGuid, APIFilt_OnActFloor))
					++onStory;
				if (ACAPI_Element_Filter(elemGuid, APIFilt_InCroppedView))
					++inView;
			}
			//DBPrintf("%d visible, %d on the view\'s floor, %d in the cropped view", visible, onStory, inView);
			ACAPI_WriteReport(GS::UniString::Printf("%d visible, %d on the view\'s floor, %d in the cropped view", visible, onStory, inView), false);

			// Switch back to the original database, because APIDb_ChangeCurrentDatabaseID tries to fetch the drawing element
			//	from the layout's database internally
			ACAPI_Database(APIDb_ChangeCurrentDatabaseID, &currentDB);
		}
		else
		{
			ACAPI_WriteReport(itoa(err, buffer, 10), true);
		}

		//DBPrintf("\n");
		ACAPI_WriteReport("\n", false);

		//DBPrintf("\tName: %s", drwLinkInfo.name);
		ACAPI_WriteReport(GS::UniString::Printf("\tName: %s", drwLinkInfo.name), false);
		//DBPrintf("\n");
		DBPrintf("\n", false);
		//DBPrintf("\tNumber %s", drwLinkInfo.number);
		ACAPI_WriteReport(GS::UniString::Printf("\tNumber %s", drwLinkInfo.number), false);
		//DBPrintf("\n");
		ACAPI_WriteReport("\n", false);

		short userId = 0;
		if (ACAPI_Database(APIDb_GetTWOwnerID, &(dbInfo.databaseUnId), &userId) == NoError)
			//DBPrintf("\tTeamWork owner ID: %d\n", userId);
			ACAPI_WriteReport(GS::UniString::Printf("\tTeamWork owner ID: %d\n", userId), false);
	}

	if (store == 1) {
		store = 0;
		ACAPI_Database(APIDb_StoreViewSettingsID, (void *)store);
	}
}// Do_ListDrawingLinks

 

 

This is basically as-is, straight from the ..\Examples folder.

However, I am getting an error with  the second to last line:

err = ACAPI_Database(APIDb_ChangeCurrentDatabaseID, &dbInfo);

 

 

		if (drwLinkInfo.linkTypeID == API_DrawingLink_ExternalViewID)
		{
			//DBPrintf("\t (internal %s, guid: %s)", (drwLinkInfo.viewType == API_ViewNodePerspective || drwLinkInfo.viewType == API_ViewNodeAxonometry) ? "3D view" : "view", APIGuidToString(drwLinkInfo.linkGuid).ToCStr().Get());
			ACAPI_WriteReport(GS::UniString::Printf("\t(1) (external %s, guid: %s)", (drwLinkInfo.viewType == API_ViewNodePerspective || drwLinkInfo.viewType == API_ViewNodeAxonometry) ? "3D view" : "view", APIGuidToString(drwLinkInfo.linkGuid).ToCStr().Get()), false);
		}
		else
		{
			ACAPI_WriteReport("NOT external link type...", false);
		}

		API_DatabaseInfo	dbInfo;
		BNZeroMemory(&dbInfo, sizeof(API_DatabaseInfo));
		dbInfo.typeID = APIWind_DrawingID;
		dbInfo.linkedElement = elem.header.guid;
		err = ACAPI_Database(APIDb_ChangeCurrentDatabaseID, &dbInfo);
		ACAPI_WriteReport(itoa(err, buffer, 10), true);

 

 

And my [ACAPI_WriteReport(itoa(err, buffer, 10), true);] produces this:

MudratDetector_0-1689105172158.png

which translates to this:

MudratDetector_1-1689105221302.png

 

Any idea what I should be looking for?

 

Thanks to all - Chris



Chris Gilmer
Intel i9-12950HX CPU @ 2.30GHz, 16 cores
NVIDIA GeForce RTX 3080
48.0 GB RAM
Windows 10 Pro 64-bit
1 REPLY 1
MudratDetector
Enthusiast

After a little more research, I realize the part of the code producing the error is not needed for what I want to do, so <Delete>...

 

I am able to successfully capture the full path of an external linked file for .dwg and .pdf files.

========================
Number of Drawings:  10
========================
	Y:\2020\2020063\Drawings\Design\20210514-Midtown_Civil Bases.dwg
	Y:\2020\2020063\Drawings\Consult\Interiors\20211130_Permit Backgr...

For .jpg files, I am trying the similarly formatted code I used above for .dwg and .pdf files,

	//
	// Pictures
	//
	GS::Array<API_Guid>  picList;
	if (ACAPI_Element_GetElemList(API_PictureID, &picList) != NoError) {
		ACAPI_WriteReport("Error in ACAPI_Element_GetElemList ().", true);
		return;
	}
	else
	{
		ACAPI_WriteReport("========================", false);
		ACAPI_WriteReport("Number of Pictures:  " + GS::UniString(itoa(picList.GetSize(), buffer, 10)), false);
		ACAPI_WriteReport("========================", false);
	}

	for (auto& guid : picList.AsConst()) {
		API_Element picElem = {};
		picElem.header.guid = guid;

		err = ACAPI_Element_Get(&picElem);

		if (err != NoError) {
			ACAPI_WriteReport(GS::UniString::Printf("\tDatabaseControl :: Do_ListDrawingLinks :: Cannot get Drawing with GUID %s.\n", APIGuidToString(guid).ToCStr().Get()), false);
			ACAPI_WriteReport("Error in ACAPI_Element_GetElemList ().", true);
			continue;
		}

 

With this code, I am able to get the collection of pictures and the collection of details, as verified by .GetSize() data.

========================
Number of Pictures:  76
========================

========================
Number of Details:  88
========================

 

But, with this code, I am not able to get full path of each.

========================
Number of Pictures:  76
========================
	DatabaseControl :: Do_ListDrawingLinks :: Cannot get link information for Drawing with GUID 275B9808-DB9E-4370-8446-8FF6A8F9A991.

	DatabaseControl :: Do_ListDrawingLinks :: Cannot get li
...

 

I am using the appropriate member of  the API_ElemTypeID structure.

MudratDetector_0-1689273597901.png

The APIDb_GetDrawingLinkID used for drawings does not translate well to pictures [APIDb_GetPictureLinkID] or details [APIDb_GetDetailLinkID].
What can I use in the place of APIDb_GetDrawingLinkID to get full paths of pictures and details?

 

thanks - chris

Chris Gilmer
Intel i9-12950HX CPU @ 2.30GHz, 16 cores
NVIDIA GeForce RTX 3080
48.0 GB RAM
Windows 10 Pro 64-bit