Download (direct link):
• xloper * stdcall xlAutoRegister(xloper *);
This function is only called from Excel 4 macro sheets when an executing macro encounters an instance of the REGISTER() macro sheet function where information about the types of arguments and return value of the function are not provided. xlAutoRegis-ter() is passed the name of the function in question and should search for the function’s arguments and then register the function properly, with all arguments specified. (See section 8.5 on page 182.) As macro sheets are deprecated, and outside the scope of this book, this function is not discussed any further. The function can safely either be omitted or can be a stub function returning a NULL pointer.
Turning DLLs into XLLs: The Add-in Manager Interface
• void stdcall xlAutoFree(xloper *);
Whenever Excel has been returned a pointer to an xloper by the DLL with the xlbit-DLLFree bit of the xltype field set, it calls this function passing back the same pointer. This enables the DLL to release any dynamically allocated memory that was associated with the xloper. Clearly the DLL can’t free memory before the return statement, as Excel would not safely be able to copy out its contents. The xlAutoFree() function and the xlbitDLLFree bit are the solution to this problem. (See also Chapter 7 Memory Management on page 161 for more about when and how to set this bit.)
Returning pointers to xlopers with the xlbitDLLFree bit set is the only way to return DLL-allocated memory without springing a memory leak. The next-best solution is to allocate memory, assign it to a static pointer, and free it the next time the function gets called.
Typically, your DLL will need to contain this function when
• returning DLL-allocated xloper strings;
• returning DLL-allocated range references of the type xltypeRef;
• returning DLL-allocated arrays of xlopers. If the array contains string xlopers that refer to memory that needs to be freed then xlAutoFree() should do this too. (See example below.)
There are a few points to bear in mind when dealing with arrays:
• The array memory pointed to by an array xloper can be static or dynamically allocated. The xlbitDLLFree bit should only be set for arrays where the memory was dynamically allocated by the DLL.
• Array elements that are strings may be static, or may have had memory allocated for them by either the DLL or Excel.
• Excel will only call xlAutoFree() for an array that has the xlbitDLLFree bit set, which should be one that was dynamically allocated in the DLL.
• A static array containing dynamic memory strings will leak memory.
• A DLL-created dynamic array containing Excel-allocated strings requires that the xlbitXLFree bit be set for each string, and xlAutoFree() needs to detect this.
• You should not pass arrays of arrays, or arrays containing references, back to Excel: your implementation of xlAutoFree() does not need to check for this. (The example implementation below would, in fact, cope fine with this, but the inclusion of a reference in an array would confuse and possibly destabilise Excel.)
The following code provides an example implementation that checks for arrays, range references and strings - the three types that can be returned to Excel with memory still needing to be freed. The function can call itself recursively when freeing array elements. For this reason the function checks for an argument that has the xlbitXLFree bit set. Excel will never call this function for an xloper with this bit set, but this implementation copes with Excel-created strings in DLL-created arrays.
Excel Add-in Development in C/C++
void stdcall xlAutoFree(xloper *p_op)
if(p_op->xltype & xltypeMulti)
// Check if the elements need to be freed then check if the array // itself needs to be freed.
int size = p_op->val.array.rows * p_op->val.array.columns; xloper *p = p_op->val.array.lparray;
for(; size-- > 0; p++)
if(p->xltype & (xlbitDLLFree | xlbitXLFree)) xlAutoFree(p);
if(p_op->xltype & xlbitDLLFree) free(p_op->val.array.lparray);
else if(p_op->xltype == (xltypeStr | xlbitDLLFree))
else if(p_op->xltype == (xltypeRef | xlbitDLLFree))
else if(p_oper->xltype | xlbitXLFree)
Excel4(xlFree, 0, 1, p_op);
Passing Data between Excel and the DLL
Where DLL functions are being accessed directly by Excel, you need to understand how to pass and return values. You need to think about the data types of both the arguments and return value(s). You need to know whether arguments are passed by reference, (by pointer, as the interface is C), or by value. You need to decide whether to return values via the function’s return value or by modifying arguments passed in by reference. Where the data you want to pass or return is not one of the simple data types, you need to know about the data structures that Excel supports and when their use is most appropriate.