xlAutoFree/xlAutoFree12
适用于:Excel 2013 | Office 2013 | Visual Studio
在 XLL 工作表函数返回 XLOPER/ XLOPER12 后,Microsoft Excel 调用,该标志集指示 XLL 仍需要释放内存。 这将会使 XLL 动态返回已分配的数组、字符串以及没有内部泄漏的工作表的外部引用。 有关更多信息,请参阅 Excel 中的内存管理。
从 Excel 2007 开始,支持 xlAutoFree12 函数和 XLOPER12 数据类型。
Excel 不需要 XLL 来实现和导出其中任一函数。 但是,如果 XLL 函数返回已动态分配或包含指向动态分配内存的指针的 XLOPER 或XLOPER12,则必须执行此操作。 确保在整个 XLL 以及实现 xlAutoFree 和 xlAutoFree12 的方式中,选择管理这些类型的内存的方式一致。
在 xlAutoFree/ xlAutoFree12 函数中,禁用对 Excel 的回调,但有一个例外:可以调用 xlFree 来释放 Excel 分配的内存。
void WINAPI xlAutoFree(LPXLOPER pxFree);
void WINAPI xlAutoFree12(LPXLOPER12 pxFree);
参数
对于 xlAutoFree) ,pxFree (LPXLOPER
对于xlAutoFree12) ,pxFree (LPXLOPER12
指向 XLOPER 或具有需要释放的内存 的XLOPER12 的指针。
属性值/返回值
此函数不返回值,应声明为返回 void。
备注
当 Excel 配置为使用多线程工作簿重新计算时,将在用于调用返回它的函数的同一线程上调用 xlAutoFree/ xlAutoFree12 。 在对该线程上的任何后续工作表单元格进行求值之前,始终调用 xlAutoFree/ xlAutoFree12。 这可以简化 XLL 中的线程安全设计。
如果提供的 xlAutoFree/ xlAutoFree12 函数查看 pxFree 的 xltype 字段,请记住,仍将设置 xlbitDLLFree 位。
示例
示例实现 1
中的第一个代码 \SAMPLES\EXAMPLE\EXAMPLE.C
演示 了 xlAutoFree 的一个非常具体的实现,该实现旨在仅处理一个函数 fArray。 通常,XLL 将有多个函数返回需要释放的内存,在这种情况下,需要限制较少的实现。
示例实现 2
第二个示例实现与第 1.6.3 节、xl12_Str_example、xl12_Ref_example 和 xl12_Multi_example 中的XLOPER12创建示例中使用的假设一致。 假设设置 xlbitDLLFree 位后,所有字符串、数组和外部引用内存都已使用 malloc 动态分配,因此需要在对 free 的调用中释放。
示例实现 3
第三个示例实现与 XLL 一致,其中导出的函数 返回XLOPER12使用 malloc 分配字符串、外部引用和数组,并且 XLOPER12 本身也是动态分配的。 返回指向动态分配 XLOPER12 的指针是确保函数线程安全的一种方法。
//////////////////////////////////////////
// BEGIN EXAMPLE IMPLEMENTATION 1
//////////////////////////////////////////
LPXLOPER12 WINAPI fArray(void)
{
LPXLOPER12 pxArray;
static XLOPER12 xMulti;
int i;
int rwcol;
xMulti.xltype = xltypeMulti | xlbitDLLFree;
xMulti.val.array.columns = 1;
xMulti.val.array.rows = 8;
// For large values of rows and columns, this would overflow
// use __int64 in that case and return an error if rwcol
// contains a number that won't fit in sizeof(int) bytes
rwcol = xMulti.val.array.columns * xMulti.val.array.rows;
pxArray = (LPXLOPER12)GlobalLock(hArray = GlobalAlloc(GMEM_ZEROINIT, rwcol * sizeof(XLOPER12)));
xMulti.val.array.lparray = pxArray;
for(i = 0; i < rwcol; i++)
{
pxArray[i].xltype = xltypeInt;
pxArray[i].val.w = i;
}
// Word of caution - returning static XLOPERs/XLOPER12s is not thread safe
// for UDFs declared as thread safe, use alternate memory allocation mechanisms
return (LPXLOPER12)&xMulti;
}
void WINAPI xlAutoFree12(LPXLOPER12 pxFree)
{
GlobalUnlock(hArray);
GlobalFree(hArray);
return;
}
//////////////////////////////////////////
// BEGIN EXAMPLE IMPLEMENTATION 2
//////////////////////////////////////////
void WINAPI xlAutoFree12(LPXLOPER12 pxFree)
{
if(pxFree->xltype & xltypeMulti)
{
/* Assume all string elements were allocated using malloc, and
** need to be freed using free. Then free the array itself.
*/
int size = pxFree->val.array.rows *
pxFree->val.array.columns;
LPXLOPER12 p = pxFree->val.array.lparray;
for(; size-- > 0; p++) // check elements for strings
if(p->xltype == xltypeStr)
free(p->val.str);
free(pxFree->val.array.lparray);
}
else if(pxFree->xltype & xltypeStr)
{
free(pxFree->val.str);
}
else if(pxFree->xltype & xltypeRef)
{
free(pxFree->val.mref.lpmref);
}
}
//////////////////////////////////////////
// BEGIN EXAMPLE IMPLEMENTATION 3
//////////////////////////////////////////
LPXLOPER12 WINAPI example_xll_function(LPXLOPER12 pxArg)
{
// Thread-safe return value. Every invocation of this function
// gets its own piece of memory.
LPXLOPER12 pxRtnValue = (LPXLOPER12)malloc(sizeof(XLOPER12));
// Initialize to a safe default
pxRtnValue->xltype = xltypeNil;
// Set the value of pxRtnValue making sure that strings, external
// references, arrays, and strings within arrays are all dynamically
// allocated using malloc.
// (code omitted)
// ...
// Set xlbitDLLFree regardless of the type of the return value to
// ensure xlAutoFree12 is called and pxRtnValue is freed.
pxRtnValue->xltype |= xlbitDLLFree;
return pxRtnValue;
}
void WINAPI xlAutoFree12(LPXLOPER pxFree)
{
if(pxFree->xltype & xltypeMulti)
{
// Assume all string elements were allocated using malloc, and
// need to be freed using free. Then free the array itself.
int size = pxFree->val.array.rows *
pxFree->val.array.columns;
LPXLOPER12 p = pxFree->val.array.lparray;
for(; size-- > 0; p++) // check elements for strings
if(p->xltype == xltypeStr)
free(p->val.str);
free(pxFree->val.array.lparray);
}
else if(pxFree->xltype & xltypeStr)
{
free(pxFree->val.str);
}
else if(pxFree->xltype & xltypeRef)
{
free(pxFree->val.mref.lpmref);
}
// Assume pxFree was itself dynamically allocated using malloc.
free(pxFree);
}