We value your input!
Please participate in Archicad 28 Home Screen and Tooltips/Quick Tutorials survey

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

[SOLVED] Crashing on SelectionChange Handler + Elem Observer

Erenford
Booster
Greetings, I'm having problems when using two Notification handlers. Basically it's a palette that uses SelectionChangeHandler to detect selected element (if wall is selected, it will show stuff) then ElemObserverHandler to detect changes from that element so the palette can update automatically. I attach elems to the observer in the SelectionChangeHandler function if it detects valid selection.

The crash happens when I do the following:
1) Open up the palette + Init handlers
2) Select an elem
3) Delete the selected elem
4) Select another elem
5) Undo-delete (Ctrl+Z). Archicad crashes immediately right after undo is pressed

Further testing:
1-3) Do actions
4) If I did not select an elem after deletion and went directly to undo-delete = no crash

Another scenario:
1-3) Do actions
4) If I multi-select elems after deletion then pressed undo = no crash

Another scenario:
1-4) Do actions
5) Un-select it, select another elem (repeated x times)
6) Undo-delete:
6a) If it has a selected elem = crash
6b) If it has no selected = no crash

Below is the code for the handlers, I've emptied the Elem Observer and palette (its created but no dialog items) so I know the SelectionChangeHandler has the problem.

API_Guid	g_guidPrev = APINULLGuid;
bool		g_hasSelected = false;

GSErrCode Observer_DetachAllElems()
{
	API_Elem_Head**     elemHead;
	Int32               nElems = 0;
	GSErrCode err = ACAPI_Element_GetObservedElements(&elemHead, &nElems);
	if (err != NoError)
	{
		WriteReport("["__FUNC__"] ERROR %s - ACAPI_Element_GetObservedElements", ErrId2Name(err));
		return err;
	}
	for (Int32 i = 0; i < nElems; i++)
	{
		err = ACAPI_Element_DetachObserver(&(*elemHead));
		if (err != NoError) WriteReport("["__FUNC__"] ERROR %s - ACAPI_Element_DetachObserver()", ErrId2Name(err));
	}
	BMKillHandle((GSHandle*)&elemHead);

	return err;
}

GSErrCode Observer_AttachElem(API_Guid guid)
{
	// Get element head
	API_Elem_Head head;
	BNZeroMemory(&head, sizeof(head));
	head.guid = guid;
	GSErrCode err = ACAPI_Element_GetHeader(&head, APIElemMask_FloorPlan);
	if (err != NoError)
	{
		WriteReport("["__FUNC__"] ERROR %s - ACAPI_Element_GetHeader()", ErrId2Name(err));
		return err;
	}
	// Attach elem to observer
	err = ACAPI_Element_AttachObserver(&head, NULL);
	if (err != NoError)
		WriteReport("["__FUNC__"] ERROR %s - ACAPI_Element_AttachObserver()", ErrId2Name(err));
	return err;
}

static GSErrCode __ACENV_CALL	ElemObserverEventHandler(const API_NotifyElementType* /*elemType*/)
{
	// Empty function
	return NoError;
}   // ElemObserverEventHandler

GSErrCode InitializeElemObserverHandler()
{
	const GSErrCode err = ACAPI_Notify_InstallElementObserver(ElemObserverEventHandler);
	if (err != NoError) DBGPrintlnf("[Error] %s "__FUNC__" - ACAPI_Notify_InstallElementObserver(ElemObserverEventHandler)", ErrId2Name(err));
	return err;
}


static GSErrCode __ACENV_CALL	SelectionChangeHandler(const API_Neig *selElemNeig)
{
	if (selElemNeig == nullptr)
		return NoError;
	if (selElemNeig->neigID == APINeig_None)
	{
		WriteReport("All elements deselected");
		if (g_hasSelected)	// Deselected (currently no selection & previously has selection)
		{
			g_hasSelected = false;
			// Detach previous elem
			Observer_DetachAllElems();
		}
		return NoError;
	}

	API_Neig** selNeigs;
	API_SelectionInfo selectionInfo;
	BNZeroMemory(&selectionInfo, sizeof(selectionInfo));
	GSErrCode err = ACAPI_Selection_Get(&selectionInfo, &selNeigs, true);
	BMKillHandle((GSHandle*)&selectionInfo.marquee.coords);
	if (err == APIERR_NOSEL)
	{
		WriteReport("["__FUNC__"] ERROR %s - ACAPI_Selection_Get()", ErrId2Name(err));
		err = NoError;
		if (g_hasSelected)	// Deselected (currently no selection & previously has selection)
		{
			g_hasSelected = false;
			// Detach previous elem
			Observer_DetachAllElems();
			BMKillHandle((GSHandle*)&selNeigs);
			return err;
		}
	}
	if (err != NoError)
	{
		WriteReport("["__FUNC__"] ERROR %s - ACAPI_Selection_Get()", ErrId2Name(err));
		BMKillHandle((GSHandle*)&selNeigs);
		return err;
	}

	if (selectionInfo.typeID != API_SelEmpty)
	{
		// collect indexes of selected dimensiosn
		const UInt32 nSel = BMGetHandleSize((GSHandle)selNeigs) / sizeof (API_Neig);
		if (nSel != 1)
		{	// exit since invalid selection, accept only single select
			BMKillHandle((GSHandle*)&selNeigs);
			return err;
		}
		// Valid selection: single select
		API_Guid guid = (*selNeigs)[0].guid;
		BMKillHandle((GSHandle*)&selNeigs);
		if (g_guidPrev == guid) // Exit now if selected elem did not change
			return NoError;

		// Detach previous elem
		Observer_DetachAllElems();

		g_guidPrev = guid;
		g_hasSelected = true;

		// Check if elem is already being observed
		API_Elem_Head**     elemHead;
		Int32               nElems = 0;
		err = ACAPI_Element_GetObservedElements(&elemHead, &nElems);
		if (err != NoError)
		{
			WriteReport("["__FUNC__"] ERROR %s - ACAPI_Element_GetObservedElements", ErrId2Name(err));
			return err;
		}
		for (Int32 i = 0; i < nElems; i++)
		{
			if ((*elemHead).guid == guid) // Exit if already observed
			{
				BMKillHandle((GSHandle*)&elemHead);
				return NoError;
			}
		}
		BMKillHandle((GSHandle*)&elemHead);

		// Attach elem to observer
		Observer_AttachElem(guid);
	}

	return NoError;
}   // SelectionChangeHandler

GSErrCode InitializeSelectionChangeHandler()
{
	const GSErrCode err = ACAPI_Notify_CatchSelectionChange(SelectionChangeHandler);
	if (err != NoError) DBGPrintlnf("[Error] %s "__FUNC__" - ACAPI_Notify_CatchSelectionChange(SelectionChangeHandler)", ErrId2Name(err));
	return err;
}
7 REPLIES 7
Ralph Wessel
Mentor
Erenford wrote:
Greetings, I'm having problems when using two Notification handlers. Basically it's a palette that uses SelectionChangeHandler to detect selected element (if wall is selected, it will show stuff) then ElemObserverHandler to detect changes from that element so the palette can update automatically. I attach elems to the observer in the SelectionChangeHandler function if it detects valid selection.
Have you debugged into this code to determine where the crash occurs? That might yield valuable clues to the source of the problem.
Ralph Wessel BArch
Software Engineer Speckle Systems
Erenford
Booster
Ralph wrote:
Have you debugged into this code to determine where the crash occurs? That might yield valuable clues to the source of the problem.
Yes I forgot to mention that. I've tried but the crash occurs even before entering the SelectionChangeHandler function. I inserted a debug print at the very start of the function, did the actions above, and it crashes before printing it, immediately right after pressing undo.

Also I've attached the BugReport dump maybe it may help. I've noticed that my addon isn't listed in the call stack, usually its there and I can pinpoint which part of my code it last ran.

This is in AC 20 6005 by the way.
Erenford
Booster
[WORKAROUND]
Ok I did a workaround for this issue by removing the Elem Observer entirely. I noticed that SelectionChangeHandler gets called anyway at probably most user action so I figured I can check the elem change in there instead of a separate handler. I tested it and it seems to work fine.

I still don't know what the cause of the crashes though.
Ralph Wessel
Mentor
Erenford wrote:
[WORKAROUND]
Ok I did a workaround for this issue by removing the Elem Observer entirely. I noticed that SelectionChangeHandler gets called anyway at probably most user action so I figured I can check the elem change in there instead of a separate handler. I tested it and it seems to work fine.

I still don't know what the cause of the crashes though.
What was the element observer doing? It wasn't trying to work on a deleted element by any chance?
Ralph Wessel BArch
Software Engineer Speckle Systems
Erenford
Booster
Ralph wrote:
What was the element observer doing? It wasn't trying to work on a deleted element by any chance?
No I only used the APINotifyElement_Change event to check new values of elem. Both event handlers were calling the same function (get elem from database then update the palette). Don't worry though as I always check if it exists or has no error otherwise it will exit the function / handler.

After I came upon the crashes I emptied the ElemObserverEventHandler to test if its the cause, but it still crashes.
Mihaly Palenik
Graphisoft
Graphisoft
Hello Erenford,

Thank you your comment. Unfortunately this is an ArchiCAD bug which is already in our bug database. We will try to do the best to fix it and place into the next update.
Erenford
Booster
Mihály wrote:
Hello Erenford,

Thank you your comment. Unfortunately this is an ArchiCAD bug which is already in our bug database. We will try to do the best to fix it and place into the next update.
Great thanks for the notification, I'll mark this as solved then.

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!