Archicad 28 C++ API
|
These functions provide a way for Add-Ons to communicate (pass data, call exposed commands) with one another. More...
Classes | |
struct | API_MDCLParameter |
Parameter structure used for inter-addon communication. More... | |
struct | API_ModulID |
Unique identifier of an add-on. More... | |
class | API_AddOnCommand |
Base class for the Add-On commands. More... | |
Typedefs | |
typedef GSErrCode | APIExternalCallBackProc(GSHandle params, GSErrCode returnCode) |
Callback function for handling the responses of asynchronous external module command calls. | |
typedef void | APICommandCallBackProc(GSHandle *paramsHandle, GSPtr resultData, GSErrCode returnCode) |
Callback function for handling the responses of asynchronous module command calls from main event loop. | |
Functions | |
GSErrCode | ACAPI_AddOnAddOnCommunication_InitMDCLParameterList (GSHandle *params) |
Initializes a parameter list to pass to an other add-on. | |
GSErrCode | ACAPI_AddOnAddOnCommunication_GetMDCLParameterNum (GSHandle params, Int32 *nPars) |
Retrieves the number of the parameters on the parameter list. | |
GSErrCode | ACAPI_AddOnAddOnCommunication_AddMDCLParameter (GSHandle params, API_MDCLParameter *mDCLParameter) |
Appends a parameter to the parameter list. | |
GSErrCode | ACAPI_AddOnAddOnCommunication_GetMDCLParameter (GSHandle params, API_MDCLParameter *mDCLParameter) |
Retrieves a parameter from the parameter list. | |
GSErrCode | ACAPI_AddOnAddOnCommunication_ChangeMDCLParameter (GSHandle params, API_MDCLParameter *mDCLParameter) |
Modifies a parameter on the parameter list. | |
GSErrCode | ACAPI_AddOnAddOnCommunication_FreeMDCLParameterList (GSHandle *params) |
Frees the parameter list handle. | |
GSErrCode | ACAPI_AddOnAddOnCommunication_RegisterSupportedService (GSType cmdID, Int32 cmdVersion) |
Registers a command which can be used by other add-ons. | |
GSErrCode | ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler (GS::Owner< API_AddOnCommand > addOnCommand) |
Installs the Add-On command handler object. | |
GSErrCode | ACAPI_AddOnAddOnCommunication_Test (const API_ModulID *mdid, GSType cmdID, Int32 cmdVersion) |
Test the availability of a command. | |
GSErrCode | ACAPI_AddOnAddOnCommunication_Call (const API_ModulID *mdid, GSType cmdID, Int32 cmdVersion, GSHandle params, GSPtr resultData, bool silentMode) |
Call a command of an other add-on. | |
GSErrCode | ACAPI_AddOnAddOnCommunication_ExternalCall (const IO::Location *projectFileLoc, const API_ModulID *mdid, GSType cmdID, Int32 cmdVersion, GSHandle params, bool silentMode, APIExternalCallBackProc *externalCallbackProc) |
Call a command of an other add-on in another Archicad instance. | |
GSErrCode | ACAPI_AddOnAddOnCommunication_CallFromEventLoop (const API_ModulID *mdid, GSType cmdID, Int32 cmdVersion, GSHandle paramsHandle, bool silentMode, APICommandCallBackProc *callbackProc) |
Calls a command of an add-on from Archicad's main event loop. | |
These functions provide a way for Add-Ons to communicate (pass data, call exposed commands) with one another.
The Communication Manager is a very powerful new service introduced in API v3.1.
In the previous versions of the API add-ons could be called by Archicad only. There were two ways to do that. The add-on could be called because of a direct user interaction, or there was a need to post a notification to it. It was not possible to call one add-on from another.
All of the communication manager functions begin with the ACAPI_AddOnAddOnCommunication_ prefix. They are as follows:
ACAPI_AddOnAddOnCommunication_Test ACAPI_AddOnAddOnCommunication_ExternalCall ACAPI_AddOnAddOnCommunication_CallFromEventLoop
There are some functions to provide easy and controlled mechanism for parameter passing. They are:
ACAPI_AddOnAddOnCommunication_InitMDCLParameterList ACAPI_AddOnAddOnCommunication_GetMDCLParameterNum ACAPI_AddOnAddOnCommunication_GetMDCLParameter ACAPI_AddOnAddOnCommunication_AddMDCLParameter ACAPI_AddOnAddOnCommunication_ChangeMDCLParameter ACAPI_AddOnAddOnCommunication_FreeMDCLParameterList
What is an entry point of an add-on? It is a function or service which can be called from another add-on with the support of the Communication Manager.
The entry points are interface independent. It means that there isn't any relationship between the commands put into the Archicad menu structure and the entry points. The first set is controlled by the ACAPI_MenuItem_RegisterMenu or ACAPI_AddOnIntegration_RegisterFileType and the like, the second type entry points are given by ACAPI_AddOnAddOnCommunication_RegisterSupportedService.
An add-on can have as many entry points as it wants, and each of them has to be registered in the RegisterInterface function of your add-on with ACAPI_AddOnAddOnCommunication_RegisterSupportedService. This function tells Archicad that the add-on can be called by another. The parameters of this function are the following:
Refer to the function description for more details.
Later in the Initialize function the add-on has to register callback function to handle the different supported commands. The ACAPI_AddOnIntegration_InstallModulCommandHandler function's parameters identify the command (with its ID and version number), and the last parameter supplies the module command handler callback function. This callback function then receives the parameters, may optionally pass back its results in a separate pointer, and is also informed whether it should run in silent mode.
An entry point is identified by the following two components:
This means that entry point IDs must be unique in the world of an add-on. Different add-ons may have the same entry point IDs, but locally an add-on is not allowed to specify the same ID more than once.
On the caller add-ons side, it may check for the existence of the necessary entry points of the target add-on in its own RegisterInterface function, with ACAPI_AddOnIntegration_RegisterRequiredService.
The last issue is version control. The caller add-on must specify the required version of the entry point also. The API assumes backward compatibility. When an add-on tests for an entry point's availability, the following cases may occur (assuming the identification was successful):
When you assign a version number to an entry point, you must adhere to the following rules:
Note that the most general cases where the compatibility issues are important are:
In either cases keep the compatibility, if possible. Upon a call of an entry point, the Communication Manager first identifies the command. Ifit is available, it checks the entry point version. If there isn't any version problem, it calls the entry point by passing the required version number. Use this data to ensure the same environment and behavior.
It is very important to understand what happens in the background when the API calls an add-on.
In general the API allocates a unique environment to each executed add-on. Normally only one add-on is executed by the API, only one add-on is in one of its callback functions. However there are cases when there are more add-ons in the call stack.
In these cases more add-ons are executed at the same time, they are all in their notification or module command handlerfunctions.
Note, that this is not a real multiprocessing architecture.
The API maintains a call stack all the time, and only the top-most add-on has the right to call the API services. This is the add-on whose environment is the active one. Once the top-most add-on has returned from its callback function, the API takes the next add-on on the stack, and makes its environment to be the active one.
So, the structure is nested, instead of being parallel.
The figure below tries to explain the system. The user has called a command which is implemented in the add-on A. add-on A calls a function of add-on B. It performs an operation which results to post a notification to add-on C.
Figure #1: the API call stack and client environments
The vertical lines show which environment is the active one. On the right side the call stack maintained by the API is shown.
On Figure #2 you can see how the CommunicationManager and CommunicationClient example projects communicate to each other.
Figure #2: communication architectures
On the left side of the picture the normal situation is shown.
Client A (which is the CommunicationManager example project) wants to call the entry point CMD1
(command 1) of client B (the CommunicationClient example project). It calls the ACAPI_AddOnAddOnCommunication_Call function with the necessary IDs. The API loads the add-on B, and calls its module command handler function, registered for the CMD1
command. When B has returned, the control goes back to the API, into the ACAPI_AddOnAddOnCommunication_Call function. It switches the environment back to the one owned by A, and returns. Client A gets the control and can continue working.
This system is quite simple, however sometimes it is not strong enough. The ACAPI_AddOnAddOnCommunication_Call function is a very robust one, with a lot of overhead. First, it has to decide whether the addressed add-on is installed. Then it has to be loaded into the memory and initialized; of course just if it is was not loaded before. The caller add-on may want to pass some parameters too, the method to do that also has a strong overhead (the details are explained later in this paper).
On the right side of the picture a more complex architecture is shown, where the two add-ons can call each other directly. For this purpose client B has implemented two special entry points:
BEGB
is to setup a binary link. Actually it just fills up a function table, or returns a pointer to a class with virtual functions initialized. The most important, that it calls the ACAPI_KeepInMemory function to forcethe API to keep it in the memory. When the ACAPI_AddOnAddOnCommunication_Call function returns to client A, he gets the necessary function pointers, and as client B is in the memory, they are valid, they can be called. From this point, client A is also allowed to pass function pointers to client B. So, an environment is set up where two add-ons can call each other directly, with the standard C/C++ calls, without the assistance of the
Communication Manager.
ENDB
is just to dispose the binary link. Actually the only task it has to do is to call the ACAPI_KeepInMemory function to sign that it can be unloaded.
What is very important to know is, that in this architecture client B is running under the API environment of client A. He can call any of the API services, but the API handles client A as the active one. The API will process these request in a way, as they would be called by client A. This critical session is shown by a zigzag type line on the picture.
Please note that from Archicad 10 it is a possible to make an add-on command execute in an external Archicad instance to perform operation on a different project file. For more details refer to the ACAPI_AddOnAddOnCommunication_ExternalCall function.
Please note that from Archicad 19 you can execute add-on command forced from main event loop using ACAPI_AddOnAddOnCommunication_CallFromEventLoop function.
Parameters should be passed in the params
argument to the ACAPI_AddOnAddOnCommunication_Call function. This handle -whose internal format is not public- is owned by the API. The content is not checkedby the API, it just simply passed to the called entry point.
The parameters should be listed in the public header file of the add-on. Each parameter is identified by its name. Each parameter has a value type, which can be either a string, integer or float type. The API does not check the passed parameters, it merely passes those onto the called add-on. Consistency must be validated by the called add-on's entry function.
The workflow is:
It is very important, that the parameters must be relative to the factory default parameters of the called add-on. The called add-on first must set up its factory default parameters, then while retrieving the passed parameters one by one, the defaults should be modified. If no parameters were passed (params == nullptr
) the factory default parameters should be used without any modification. Another important note is that the parameters must be interpreted in the same order as they have been passed.
The above rules ensure that the execution of the entry points will not be context sensitive. No matter what the current defaults are (saved into the preferences), parameters are interpreted based on the factory defaults. It doesn't matter that some parameters are not passed to the client, as they have defaults.
Let's take an example.
The DXF/DWG add-on exports an entry point the open an AutoCAD drawing. Its options dialog also has a Default button to set and use the factory default parameters. The add-on emulates the behavior of this dialog while interpreting the passed parameters.
The caller add-on can disable all interface elements of the called add-on with the silentMode
parameter.
If this parameter is set to true
, the called add-on is not allowed to open its dialogs and alerts. In the case it is false
the option dialog must appear; of course after processing the passed parameters. The user is allowed to modify any parameter. In the case the modifications may have an effect on the passed parameters, use the ACAPI_AddOnAddOnCommunication_ChangeMDCLParameter function to allow the caller add-on to track the changes.
There are two ways to return parameters to the caller.
The default option is to use the return value of the ACAPI_AddOnAddOnCommunication_Call call. The value returned by this function is the value returned by the client's module command handler function.
The other way is to use the resultData
parameter. This is a simple pointer, which can be used for any purpose. The specification must be given by the called add-on.
It is absolutely necessary to provide developer documentation for each add-on which publishes its interface. This document should give details what the functionality of the entry point is, what parameters can be passed, how they are interpreted and what return vales are provided.
By default put this document into the same folder where your add-on is installed.
typedef void APICommandCallBackProc(GSHandle *paramsHandle, GSPtr resultData, GSErrCode returnCode) |
Callback function for handling the responses of asynchronous module command calls from main event loop.
paramsHandle | [in/out] pointer to the passed parameters for the module command |
resultData | [in] optional result data from the APIModulCommandProc function of the server side add-on |
returnCode | [in] the return value of the APIModulCommandProc function of the server side add-on |
typedef GSErrCode APIExternalCallBackProc(GSHandle params, GSErrCode returnCode) |
Callback function for handling the responses of asynchronous external module command calls.
params | [in/out] the passed parameters for the module command |
returnCode | [in] the return value of the APIModulCommandProc function of the server side add-on |
GSErrCode ACAPI_AddOnAddOnCommunication_AddMDCLParameter | ( | GSHandle | params, |
API_MDCLParameter * | mDCLParameter | ||
) |
Appends a parameter to the parameter list.
params | [in/out] Handle of the parameter list |
mDCLParameter | [in] Pointer to the parameter to be appended |
GSErrCode ACAPI_AddOnAddOnCommunication_Call | ( | const API_ModulID * | mdid, |
GSType | cmdID, | ||
Int32 | cmdVersion, | ||
GSHandle | params, | ||
GSPtr | resultData, | ||
bool | silentMode | ||
) |
Call a command of an other add-on.
mdid | [in] the identifier of the target add-on. It is defined by the 'MDID' resource. |
cmdID | [in] the identifier of the command to be executed. |
cmdVersion | [in] the required command version |
params | [in/out] passed parameters (optional). See the Inter-add-on communication section of the ACAPI_Goodies functions |
resultData | [out] results returned by the command (optional) |
silentMode | [in] instruct the target add-on to work in silent mode. No option dialogs, error alerts...etc. |
GSErrCode ACAPI_AddOnAddOnCommunication_CallFromEventLoop | ( | const API_ModulID * | mdid, |
GSType | cmdID, | ||
Int32 | cmdVersion, | ||
GSHandle | paramsHandle, | ||
bool | silentMode, | ||
APICommandCallBackProc * | callbackProc | ||
) |
Calls a command of an add-on from Archicad's main event loop.
mdid | [in] the identifier of the target add-on. It is defined by the 'MDID' resource |
cmdID | [in] the identifier of the command to be executed |
cmdVersion | [in] the required command version |
paramsHandle | [in/out] passed parameters (optional). See the Inter-add-on communication section of the ACAPI_Goodies functions |
silentMode | [in] instruct the target add-on to work in silent mode. No option dialogs, error alerts...etc. |
callbackProc | [in] optional callback procedure for handling the responses asynchronously |
GSErrCode ACAPI_AddOnAddOnCommunication_ChangeMDCLParameter | ( | GSHandle | params, |
API_MDCLParameter * | mDCLParameter | ||
) |
Modifies a parameter on the parameter list.
params | [in/out] Handle of the parameter list |
mDCLParameter | [in] Pointer to the modified parameter |
GSErrCode ACAPI_AddOnAddOnCommunication_ExternalCall | ( | const IO::Location * | projectFileLoc, |
const API_ModulID * | mdid, | ||
GSType | cmdID, | ||
Int32 | cmdVersion, | ||
GSHandle | params, | ||
bool | silentMode, | ||
APIExternalCallBackProc * | externalCallbackProc | ||
) |
Call a command of an other add-on in another Archicad instance.
projectFileLoc | [in] the location of the project file to be opened during the remote call |
mdid | [in] the identifier of the target add-on. It is defined by the 'MDID' resource |
cmdID | [in] the identifier of the command to be executed |
cmdVersion | [in] the required command version |
params | [in/out] passed parameters (optional). See the Inter-add-on communication section of the ACAPI_Goodies functions |
silentMode | [in] instruct the target add-on to work in silent mode. No option dialogs, error alerts...etc. |
externalCallbackProc | [in] optional callback procedure for handling the responses asynchronously |
GSErrCode ACAPI_AddOnAddOnCommunication_FreeMDCLParameterList | ( | GSHandle * | params | ) |
Frees the parameter list handle.
params | [in] Handle of the parameter list |
GSErrCode ACAPI_AddOnAddOnCommunication_GetMDCLParameter | ( | GSHandle | params, |
API_MDCLParameter * | mDCLParameter | ||
) |
Retrieves a parameter from the parameter list.
params | [in] The handle of the parameter list |
mDCLParameter | [out] Pointer to the requested parameter |
GSErrCode ACAPI_AddOnAddOnCommunication_GetMDCLParameterNum | ( | GSHandle | params, |
Int32 * | nPars | ||
) |
Retrieves the number of the parameters on the parameter list.
params | [in] The handle of the parameter list |
nPars | [out] Number of the parameters on the list |
GSErrCode ACAPI_AddOnAddOnCommunication_InitMDCLParameterList | ( | GSHandle * | params | ) |
Initializes a parameter list to pass to an other add-on.
params | [out] The address of a handle to be initialized |
GSErrCode ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler | ( | GS::Owner< API_AddOnCommand > | addOnCommand | ) |
Installs the Add-On command handler object.
addOnCommand | [in] The Add-On command handler object. After the ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler is called, the ownership is passed and the object can not be used. |
ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler
function should be called from Initialize. After a successful ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler
function call, the Add-On stays in the memory. GSErrCode ACAPI_AddOnAddOnCommunication_RegisterSupportedService | ( | GSType | cmdID, |
Int32 | cmdVersion | ||
) |
Registers a command which can be used by other add-ons.
cmdID | [in] The command identifier of the supported service. |
cmdVersion | [in] The command version of the supported service. |
GSErrCode ACAPI_AddOnAddOnCommunication_Test | ( | const API_ModulID * | mdid, |
GSType | cmdID, | ||
Int32 | cmdVersion | ||
) |
Test the availability of a command.
mdid | [in] the identifier of the target add-on. It is defined by the 'MDID' resource. |
cmdID | [in] the identifier of the command to be tested. |
cmdVersion | [in] the required command version |