Migration Guide

Summary: This document discusses the steps every developer should perform to port her/his add-on to ARCHICAD 8 and 8.1.

  1. Introduction
  2. Areas of modification
    1. Resources
    2. Code changes
    3. Module changes
  3. Changes in detail
    1. Add-on configuration
    2. ACAPI_String_xxx is dead
    3. ACAPI_xxxHandle is dead
    4. ACAPI_File_xxx, ACAPI_Folder_xxx, ACAPI_FileDefRec_xxx are dead
    5. Macintosh-specific types and constants removed
    6. Selection handling
    7. Undo
    8. Element linking and user data
    9. Notifications
    10. Storing and retrieving preferences
    11. Dimensions
    12. ACAPI_ModelessInit dead
    13. (Mac) extra entry points eliminated
    14. (Mac) Carbonization
    15. User controls
    16. ACAPI_UseOwnResFile/ACAPI_ResetResFile renamed
    17. Built-in library parts
    18. Changes in elements
    19. Creating library parts

0. Introduction

If you already have migrated to ARCHICAD 8, you will not have too much to do. The API interface is source compatible between these two versions, which means you have to re-compile your add-on with this DevKit, and it will run with ARCHICAD 8.1. In order to maintain the correct functionality please pay attention to the New Features, and adjust your code if it is necessary.

If you have not migrated to ARCHICAD 8 yet, then be prepared for a long and adventurous journey through the realms of the API for ARCHICAD 8 and 8.1.

We felt it was time for a change. From its first appearance as such in ARCHICAD 6.0, through 6.5 up to the recent 7.0 version the API kept its backward compatibility, so you could get your 6.0 add-on running with 7.0 without any problem. Hey, we even kept the bugs which existed in the past versions, so that you shouldn’t change your code…

With the arrival of ARCHICAD 8, the vision of a new, more robust, more powerful API emerged. As ARCHICAD itself was cut neatly into many separate modules, so was the API changing. Things disappeared, many new possibilities opened up. This was also the reason why we dropped the idea of binary compatibility in a quite early stage of the development of ARCHICAD 8.

We are also sure that many more small modifications will be necessary because of the restructuring of ARCHICAD; we’ll try to cover as much as possible by extending this document, and later with additional technical notes.

Let’s see step-by-step what this means to YOU.


1. Areas of modification

Below you’ll find a short checklist of the issues you may encounter when using the new General API DevKit 4.x.

1.a Resources

  • ACNF is not used any more
  • grc format of UserControls has changed
  • control IDs cannot be used any more
  • OWND resource is not needed any more
  • menu strings now should have prompt strings
  • a new menu item modifier was added to enable add-ons over Detail windows (^ED)

1.b Code changes

  • ACAPI_String_xxx functions are dead
  • ACAPI_xxxHandle functions are dead
  • ACAPI_File_xxx, ACAPI_Folder_xxx, ACAPI_FileDefRec_xxx functions are dead
  • Macintosh-specific variables and types are replaced with own types
  • selection handling changed
  • more control over undoable steps
  • element linking has changed
  • notifications were changed
  • DoCommand is replaced by individual callback functions
  • CheckEnvironment and RegisterInterface functions are introduced instead of the ACNF resource
  • saving preferences-like data has changed
  • API_MenuItemRef is used now instead of API_MenuParams
  • dimension handling has changed
  • ACAPI_ModelessInit is dead
  • (Mac) the extra entry points for C++ are not necessary any more
  • (Mac) Carbonization
  • ACAPI_UseOwnResFile/ACAPI_ResetResFile has been renamed
  • you can build library parts into your add-on

Some of these changes are a simple matter of replacing the old function names with new ones, whereas some other changes require restructuring or rewriting parts of your code. Other subtle changes are also happening; this document will be extended with those issues when they become relevant to you.

1.c Module changes

  • GSRoot instead of GSBase
  • DG now has an optional C++ interface
  • DG now has file/folder dialogs
  • new modules were introduced: IO (more to come)
  • UserControls now have callback functions

2. Changes in detail

Let’s see these changes in detail.

2.a Add-on configuration

The functionality of the ACNF resource has been replaced by a more flexible registration mechanism, where ARCHICAD calls special callback functions (CheckEnvironment and RegisterInterface) in your add-on while enumerating the add-ons. These functions should return what functionality your add-on provides for ARCHICAD and for other add-ons, and what interface elements (file types, menu items, toolbox icon) it would like to add to ARCHICAD’s interface. Also here you can check the running environment of your add-on, and decide whether it can run under the given conditions (e.g. disable it in the demo version of ARCHICAD).

Instead of one single entry point (DoCommand), your add-on should now register callback functions to handle requests from the server application. This should happen in the Initialize function of the add-on. So far saved preferences were passed onto the add-on as a parameter of the DoCommand function; this is replaced by the ACAPI_GetPreferences/ACAPI_SetPreferences functions. These routines now include a version number to enhance compatibility between different add-on versions; see the preferences example below.

Your add-on also received project event notifications automatically whenever it chose to stay in memory. This is no longer the case; you’ll have to register with ACAPI_Notify_CatchProjectEvent to receive these events as well.

Installing a notification handler also means that your add-on is kept in memory, without calling ACAPI_KeepInMemory.

Example:

In the grc file:

'STR#' 32500 "Menu String" {
/* [  1] */ "Active Layer^32500"
}

'STR#' 32520 "Menu prompt string" {
/* [  1] */ "Sets the active layer"
}

'STR#' 32000 "Add-On info strings" {
/* [  1] */ "Active Layer"
/* [  2] */ "All subsequently placed elements can use one common layer or their own layer."
}

In the source file:

// -----------------------------------------------------------------------------
// Dependency definitions
// -----------------------------------------------------------------------------
API_AddonType    __ACENV_CALL    CheckEnvironment (API_EnvirParams* envir)
{
    RSGetIndString (&envir->addOnInfo.name, 32000, 1, ACAPI_GetOwnResModule ());
    RSGetIndString (&envir->addOnInfo.description, 32000, 2, ACAPI_GetOwnResModule ());

    return APIAddon_Normal;
}        // CheckEnvironment


// -----------------------------------------------------------------------------
// Interface definitions
// -----------------------------------------------------------------------------
GSErrCode    __ACENV_CALL    RegisterInterface (void)

{
    //
    // Register menu(s)
    //
    GSErrCode err = ACAPI_Register_Menu (32500, 32520, MenuCode_Options1, MenuFlag_Default);

    return err;
}       // RegisterInterface


// -----------------------------------------------------------------------------
// Called after the add-on has been loaded into memory
// -----------------------------------------------------------------------------
GSErrCode    __ACENV_CALL Initialize (void)

{
    GSErrCode      err;

    err = ACAPI_Install_MenuHandler (32500, MenuCommandHandler);
    if (err != NoError)
        DBPrintf ("Initialize(): ACAPI_Install_MenuHandler failed\n");

    return err;
}        // Initialize

2.b ACAPI_String_xxx is dead

These routines have been replaced by the CHxxx routines in the GSRoot module (see the CH.hpp header file). Most of these changes can be automated with a Perl script. Note that in some cases the order of parameters have been reversed (like ACAPI_String_Copy vs CHCopyC). The table below shows the old function names and the replacement routines.

Old routine Replacement routine
ACAPI_String_Cmp (str1, str2, true/false) CHCompareCStrings (str1, str2, CS_CaseSensitive/CS_CaseInsensitive, CC_Default)
ACAPI_String_Copy (dest, source, size) CHTruncate (source, dest, sizeof (dest))
ACAPI_StringCharBytesSys (...) CHCharBytes (...)
ACAPI_String_Truncate (str, maxlen) CHTruncate (str, targetStr, maxlen + 1)
ACAPI_String_Equal (str1, str2, true/false) CHEqualCStrings (str1, str2, CS_CaseSensitive/CS_CaseInsensitive, CC_Default)
ACAPI_String_SearchRChr (str, ch) CHSearchCharRight (ch, str, strlen (str), CC_Default)
ACAPI_String_SearchLChr (str, ch) CHSearchCharLeft (ch, str, strlen (str), CC_Default)

Beside these the CHxxx routines provide additional functionality, for example conversion between UniCode and ANSI.

2.c ACAPI_xxxHandle is dead

This functionality is now available solely through the GSRoot package. In the 2.2 version of the API the use of the BMxxx routines was optional; those who made the transition back at that time spare some time now.

The table below shows the old function names and their new equivalents.

Old API name Full new name Short new name
ACAPI_NewHandle (size) BMAllocateHandle (size, ALLOCATE_CLEAR, 0) BMhAll (size)
ACAPI_DisposeHandle ((Handle) h) BMKillHandle ((GSHandle *) &h) BMhKill (&h)
ACAPI_Resize_Handle (...) BMReallocHandle (...,REALLOC_CLEAR, 0) BMhSetSize (...)
ACAPI_GetHandleSize (...) BMGetHandleSize (...) BMhSize (...)
ACAPI_LockHandle (a) hs = BMModifyHandleState (a, HANDLE_STATE_LOCK, 0)
(type of hs is char)
BMhLock ()
ACAPI_UnLockHandle (a) BMModifyHandleState (a, HANDLE_STATE_SET, hs) BMhUnlock ()

Note: MacOS X is much more sensible to memory errors. See the Carbonization Guide for more details.

2.d ACAPI_File_xxx, ACAPI_Folder_xxx, ACAPI_FileDefRec_xxx are dead

The functionality of these functions are now available in the new IO module. The FileDefRec structure for storing platform-independent paths is replaced by the IO::Location class. This affects all those API structures that worked with FileDefRec-s before. It is not straightforward to rewrite your code to use the new module, watch your hands carefully.

Also, the new file and folder dialogs in the DG module work with IO::Location-s.

2.e Macintosh-specific types and constants removed

The following Macintosh-specific constants and types were removed from the API interface, and were replaced by platform-independent types and constants.

Mac type GS type
Boolean bool
Handle GSHandle
nil nullptr
OSErr GSErrCode
noErr NoError
Ptr GSPtr

Also, API error codes will be moved to their own namespace.

2.f Selection handling

In previous API versions you had to loop through the selection, retrieve each selected element one by one, then work on it. In many cases this lead to two loops: in the first you collected the selected elements, then worked on this collection later somewhere else in your code. Now the API contains an ACAPI_Selection_Get routine, which combines the ACAPI_Selection_Init and ACAPI_Selection_GetNext functions into one single routine, and returns the selected elements in a GSHandle. It also replaces the ACAPI_Selection_GetInfo function, returning the same information in its first parameter. Along with this, the ACAPI_Element_Select function has also changed. You can now call it with more than one element.

Don’t forget to dispose the allocated GSHandle!

GSErrCode ACAPI_Selection_Get (API_SelectionInfo *selectionInfo, API_Neig*** selNeigs, bool onlyEditable);

GSErrCode ACAPI_Element_Select (API_Neig **selNeig, Int32 nItem, bool add);

2.g Undo

Your add-on is now responsible telling ARCHICAD when and where it would like to perform an undoable step. This also means you’ll have to provide a character string that appears in the Edit menu, after “Undo “. The function that performs the undoable action has to be encapsulated in a command scope:

GSErrCode ACAPI_CallUndoableCommand (GS::UniString& undoString, const std::function<GSErrCode ()>& command);

An add-on can only add one undoable step in one session. If you forget to call database modifications (e.g. ACAPI_Element_Create, or ACAPI_Element_Change) in an undoable command scope (ACAPI_CallUndoableCommand), those database modifier API functions will return APIERR_REFUSEDCMD. However, there are certain exceptions to this rule: those operations that cannot be “undone” (e.g. element creation in an I/O add-on, or in an API listing window) won’t return with this error.

One more note about using undo and rebuild: please close the undoable session before you issue any rebuild command; if you do that in reverse order, you’ll mess up the drawing update.

2.h Element linking and user data

The format of the APIElement_UserData structure has changed, new fields store the information which you had to set previously in the OWND resource. The limitation on the size of user data (128 bytes in previous API versions) is completely removed, now the information is stored in a handle. The owner ID will be the same as the module ID, you’ll also have to provide version and platform information. A new function has been introduced, which removes the user data from an element: ACAPI_Element_DeleteUserData.

So far the most widely used way of linking two elements was to store the unique IDs of the linked elements in every element as user data. The original purpose of introducing element based user data was to store information characteristic to that element, for example heat loss in a certain wall. The user data goes back to its original roots in 8; and the API provides new routines to link elements together. These are:

GSErrCode ACAPI_Element_Link (API_Guid guid_linkFrom, API_Guid guid_linkTo, GSFlags linkFlags);

GSErrCode ACAPI_Element_Unlink (API_Guid guid_linkFrom, API_Guid guid_linkTo);

GSErrCode ACAPI_Element_GetLinks (API_Guid guid_linkFrom, API_Guid ***guid_linkTo, Int32 *nLinks);

GSErrCode ACAPI_Element_GetLinkFlags (API_Guid guid_linkFrom, API_Guid guid_linkTo, GSFlags *linkFlags);

When two elements are linked together, you’ll also have to install an element observer (with a callback function), which is then called whenever the observed element changes. The add-on then retrieves the element(s) linked to the observed element, and updates those elements accordingly. To reduce complexity, the add-on should provide only one single callback function for all observed elements. You can add some custom data to link in last parameter of the ACAPI_Element_Link function, and you can get that information back with ACAPI_Element_GetLinkFlags.

2.i Notifications

The notification mechanism has slightly changed. In 8 you’ll have to register callback functions to those events you are interested in. So instead of the original Boolean parameter to switch the sending of the notifications on/off you’ll find callback functions (see below). Also, add-ons staying in memory won’t be notified automatically about open/save/etc., you’ll have to register your add-on to receive the notification for these events with ACAPI_Notify_CatchProjectEvent.

GSErrCode ACAPI_Notify_CatchProjectEvent (GSFlags eventTypes, APIProjectEventHandlerProc *handlerProc);

GSErrCode ACAPI_Notify_CatchToolChange (APIToolChangeHandlerProc *handlerProc);

GSErrCode ACAPI_Notify_CatchSelectionChange (APISelectionChangeHandlerProc *handlerProc);

GSErrCode ACAPI_Notify_CatchChangeDefaults (const API_ToolBoxItem *elemType, APIDefaultsChangeHandlerProc *handlerProc);

GSErrCode ACAPI_Notify_CatchNewElement (const API_ToolBoxItem *elemType, APIElementEventHandlerProc *handlerProc);

GSErrCode ACAPI_Notify_InstallElementObserver (APIElementEventHandlerProc *handlerProc);

The only new functionality here is the last routine, which switches the working method to an Observer model (see Design Patterns). You don’t have to assign any user data or establish a link for a certain element to receive notifications when it is modified/deleted. This handler function will be called when you tell ARCHICAD you would like to monitor changes of a certain element with ACAPI_Element_AttachObserver.

A new notification method for custom windows is also introduced, where you also have to provide a callback procedure when you create a new custom window. Notifications on library changes are also posted.

2.j Storing and retrieving preferences

Previously preferences-like data was passed onto your add-on as a parameter of the DoCommand function. As this single entry point vanished in 8, the API provides you two new functions (ACAPI_GetPreferences, ACAPI_SetPreferences) to achieve the same functionality. The ACAPI_SetPreferences routine is a simple replacement for ACAPI_RestoreOptions.

GSErrCode ACAPI_SetPreferences (Int32 version, GSSize nByte, const void* data);

GSErrCode ACAPI_GetPreferences (Int32* version, GSSize* nByte, void* data);

Example for retrieving the preferences:


    Int32       version;
    GSSize      nBytes;
    GSPtr       pref;

    ACAPI_GetPreferences (&version, &nBytes, nullptr);             // (1) get version and size
    if (version == MY_PREFERENCES_VERSION) {                    // (2) check version
        pref = BMAllocatePtr (nBytes, ALLOCATE_CLEAR, 0);       // allocate memory for preferences
        if (pref != nullptr) {
            ACAPI_GetPreferences (&version, &nBytes, pref);     // get actual preferences
            // do something with the preferences data

            BMKillPtr (&pref);                                  // dispose allocated pointer
        }
    }

Notes:

  1. Setting the last parameter to nullptr means the API will return only the version number and the size of the preferences data. If the size or the version number is 0, then no preferences were stored.
  2. Version information can be used to convert older preferences to the current format.

2.k Dimensions

The internal structure of API_DimElem has changed.

2.l ACAPI_ModelessInit dead

You have to use DGModelessInit (DG::Palette if you plan to use the C++ interface of DG) instead. Still, you’ll have to inform the API that your add-on opens a modeless palette, so that ARCHICAD should be aware of your window. This is now achieved by calling ACAPI_RegisterModelessWindow in the initialization section of your dialog callback function, and ACAPI_UnregisterModelessWindow in the termination section of the callback.

GSErrCode ACAPI_RegisterModelessWindow (Int32 referenceID, APIPaletteControlCallBackProc* callBackProc, GSFlags controlFlags);

GSErrCode ACAPI_UnregisterModelessWindow (Int32 referenceID);

The flags which informed the API when and where you wanted your window appear now became the last parameter of the ACAPI_RegisterModelessWindow function. The second parameter of this function is another callback function. So far the API sent special DG messages to the palette’s callback function to inform your add-on about certain changes in the environment (e.g. the user was performing an input). These messages (palette hide/show, disable/enable items etc.) are now passed onto this APIPaletteControlCallBackProc.

2.m (Mac) extra entry points eliminated

On Macintosh, if you wrote your add-on in C++, special shared library entry and termination points were needed, otherwise all static and global variable constructors and destructors were not called correctly. This code has been moved to the appropriate functions in ACAPlib.o, so you can remove this part of your code (these functions were usually called InitAPX and TerminateAPX).

2.n (Mac) Carbonization

If you haven’t done so, you should “carbonize” your add-on, i.e. make it work on MacOS X. The details of this process can be found in a separate Carbonization Guide (downloadable from the developers’ web site).

2.o User controls

In 7.0 you could use the attributes in the server application by simply specifying the appropriate constants in the grc file. This was implemented by using the default callback functions of the server application. These were removed in 8, but to help you we still provide default callbacks in API to set up the user controls with the actual attribute set.

Example:


    API_UCCallbackType   ucb;
    GSErrCode            err;

    // in DG_MSG_INIT
    // initialize user controls
    BNZeroMemory (&ucb, sizeof (ucb));
    ucb.dialogID = dialogID;                        // dialog ID
    ucb.type     = APIUserControlType_Layer;        // this is a layer popup
    ucb.itemID   = itemID;                          // user control's item ID
    err = ACAPI_Interface (APIIo_SetUserControlCallbackID, &ucb, nullptr);

Also, the grc format of user control 257 and 261 has changed, those constants which describe the type, appearance and other characteristics of the popup were modified.

Change your GRC file: the general rule for UC 257 is:

  • chop off the first three 0-s from the five short values
  • add a 0 at the end
  • clear the upper byte of the original 4th short, e.g. if it was 0x0704, then it should become 0x0004.

Example:

Material control in 7.0:
  0  0  0  0x0704  0x3100
becomes material control in 8:
  0x0004 0x3100 0

More examples:

Control type GRC
layer
 /* [ 12] */ UserControl    41  484  190   21  257 0x0006 0x0000 0
material
 /* [ 13] */ UserControl    41  451  190   24  257 0x0004 0x3100 0
pen
 /* [ 14] */ UserControl    87   82   33   19  257 0x0001 0x1100 0
small button menu
 /* [ 15] */ UserControl   311  331   12   12  257 0x0005 0x0600 0
line type
 /* [ 16] */ UserControl   348   39  170   40 261 0x0100

 

2.p ACAPI_UseOwnResFile/ACAPI_ResetResFile has been renamed

Both of the functions has been renamed to be more consistent with the new interface. Also, the type of the return value and the parameters were changed from short to GSResModule. Beware: this type is a Int32, not a short!

Old name New name
ACAPI_UseOwnResFile ACAPI_UseOwnResModule
ACAPI_UseOwnResFile ACAPI_UseOwnResModule

2.q Built-in library parts

With the new subtype system, you have a lot more control over library parts coming with your add-on. Actually these can be embedded into the add-on, and ARCHICAD can load the library parts directly from it. The only thing you’ll have to do to call ACAPI_Register_BuiltInLibrary. You can also register new subtypes with ACAPI_Register_Subtype.

2.r Changes in elements

Two new element types were introduced, API_PolyLineType and API_DetailType, to handle the new elements in ARCHICAD 8. The polyline data is very similar to that of the API_Polygon, the difference is that the x component of the coordinate 0 is set to -1.0. The detail drawing marker covers the marker on the floor plan; its handling is -to a certain extent- is similar to the section mark.

The dimension marker for windows and doors became library-part based. This means that form now on you’ll have to access the dimension marker’s parameters through the well-known API_AddParType structure.

The ACAPI_Element_Change function has been turbocharged to handle all element types correctly.

2.s Creating library parts

Set the isPlaceable field of the API_LibPart structure before calling ACAPI_LibPart_Create, so that the user will be able to place the created library onto the floor plan.