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);
}

另请参阅

加载项管理器和 XLL 接口函数