The ObjectARX function acedInvoke() in one application is used to call external functions defined and implemented by other ObjectARX applications. The external function called by acedInvoke() must be defined by a currently loaded ObjectARX application.
The acedInvoke() function calls the external function by the name that its application has specified in the acedDefun() call, which is the function name that AutoLISP calls to invoke the function. If the external function was defined as an AutoLISP command, with “C:” as a prefix to its name, these characters must be included in the string that acedInvoke() specifies (as when the command is invoked with an AutoLISP expression).
The name of the external function, and any argument values that it requires, is passed to acedInvoke() in the form of a linked list of result buffers. It also returns its result in a result-buffer list; the second argument to acedInvoke() is the address of a result-buffer pointer.
The following sample function calls acedInvoke() to invoke the factorial function fact() in the sample program fact.cpp:
static void test() { int stat, x = 10; struct resbuf *result = NULL, *list; // Get the factorial of x from file fact.cpp. list = acutBuildList(RTSTR, "fact", RTSHORT, x, RTNONE); if (list != NULL) { stat = acedInvoke(list, &result); acutRelRb(list); } if (result != NULL) { acutPrintf("\nSuccess: factorial of %d is %d\n", x, result->resval.rint); acutRelRb(result); } else acutPrintf("Test failed\n"); }
If a function is meant to be called with acedInvoke(), the application that defines it should register the function by calling acedRegFunc(). (In some cases the acedRegFunc() call is required, as described later in this section.) When acedRegFunc() is called to register the function, ObjectARX calls the function directly, without going through the application's dispatch loop. To define the function, call acedRegFunc().
An external function handler registered by acedRegFunc() must have no arguments and must return an integer (which is one of the application result codes—either RSRSLT or RSERR).
The following excerpt shows how the funcload() function in fact.cpp can be modified to register its functions as well as define them:
typedef int (*ADSFUNC) (void); // First, define the structure of the table: a string // giving the AutoCAD name of the function, and a pointer to // a function returning type int. struct func_entry { char *func_name; ADSFUNC func; }; // Declare the functions that handle the calls. int fact (void); // Remove the arguments int squareroot (void); // Here we define the array of function names and handlers. // static struct func_entry func_table[] = { {"fact", fact}, {"sqr", squareroot}, }; ... static int funcload() { int i; for (i = 0; i < ELEMENTS(func_table); i++) { if (!acedDefun(func_table[i].func_name, i)) return RTERROR; if (!acedRegFunc(func_table[i].func, i)) return RTERROR; } return RTNORM; }
As the code sample shows, the first argument to acedRegFunc() is the function pointer (named after the function handler defined in the source code), and not the external function name defined by acedDefun() and called by AutoLISP or acedInvoke(). Both acedDefun() and acedRegFunc() pass the same integer function code i.
If a registered function is to retrieve arguments, it must do so by making its own call to acedGetArgs().
The acedGetArgs() call is moved to be within the function fact(). The result-buffer pointer rb is made a variable rather than an argument. (This doesn't match the call to fact() in the dofun() function elsewhere in this sample. If all external functions are registered, as this example assumes, the dofun() function can be deleted completely; see the note that follows this example.) The new code is shown in boldface type:
static int fact() { int x; struct resbuf *rb; rb = acedGetArgs(); if (rb == NULL) return RTERROR; if (rb->restype == RTSHORT) { x = rb->resval.rint; // Save in local variable. } else { acdbFail("Argument should be an integer."); return RTERROR; } if (x < 0) { // Check the argument range. acdbFail("Argument should be positive."); return RTERROR; } else if (x > 170) { // Avoid floating-point overflow. acdbFail("Argument should be 170 or less."); return RTERROR; } acedRetReal(rfact(x)); // Call the function itself, and // return the value to AutoLISP. return RTNORM; }
A comparable change would have to be made to squareroot().
If a function call starts a calling sequence that causes a function in the same application to be called with acedInvoke(), the latter function must be registered by acedRegFunc(). If the called function isn't registered, acedInvoke() reports an error. The following figure illustrates this situation:
In the illustration above,
where application A defines A_tan() and A_pi(), application B defines B_sin(), and application C defines C_cos(). The A_pi() function must be registered by acedRegFunc().
To prevent acedInvoke() from reporting registration errors, register any external function that is meant to be called with acedInvoke().
The acedRegFunc() function can be called also to unregister an external function. The same application must either register or unregister the function; ObjectARX prohibits an application from directly managing another application.