Excel xll 函数能否指示返回值应显示为日期而不是数字?

问题描述

Excel“日期”在幕后是双打,XLOPER 结构似乎没有任何日期概念,只有 xltypeNum(与 VBA 中的 Variants 不同)。

我有一个简单的 XLL,它的函数不接受任何参数,将今天的日期作为 LPXLOPER(类型“P”)返回。我有其他函数通常返回日期但也可能返回错误,这就是为什么我使用“P”作为返回值而不是“B”。

DLLEXPORT LPXLOPER WINAPI epToday()
{
    static XLOPER xResult;// Return value

    xResult.xltype = xltypeNum;
    xResult.val.num = ExcelDateForToday(); //A function that returns a double for today's date

    return &xResult;
}

返回值在调用电子表格中显示为数字(例如 40303)。我希望能够告诉 Excel 将我返回的双精度值视为日期:与内置函数 TODAY() 一样。有没有办法做到这一点?

我看到 =TODAY() 将单元格 NumberFormat 更改为“Date”,我应该使用回调来更改调用单元格的格式吗?这似乎是 Excel 正在做的:例如,如果我使用 =TODAY() 函数重新计算单元格,它会再次将 NumberFormat 设置为 Date。

解决方法

据我所知,遵循通过回调设置日期格式的 TODAY() 方法是向 Excel 发出信号表明您从 XLL 函数返回的值是日期的唯一方法。但是,它确实有一些缺点:

  1. 性能(对于大量调用,虽然我还没有检查过)
  2. 如果调用者不是工作表,则需要特殊处理
  3. =TODAY() - AnotherDate 做错事,但 Excel 也做错了!
  4. 将在每次重新计算时覆盖格式 - 如果首选另一种格式,可能会惹恼用户

Excel 能够通过检测它是否作为计算周期的一部分被调用来神奇地避免 (4) - 我不知道如何在没有看到 Excel 源代码的情况下实现这一点。您可以将您的功能包装在一些东西中以设置格式,该格式将为用户提供选择(或撤消您的格式更改,因为回调将排在第二位),例如=SetFormat(MyToday(),"yyyy-mm-dd")

xlOil 中的回调相当简单(免责声明:我写的):

  XLO_FUNC_START(testToday())
  {
    CallerInfo caller;
    if (!caller.fullSheetName().empty()) // Check caller is a worksheet
      excelPost([=] 
      {
        excelApp().Range[caller.writeAddress().c_str()]->NumberFormat = L"dd-mm-yyyy"; 
      });
    std::tm buf; 
    auto now = std::time(0);
    localtime_s(&buf,&now); // Slightly labourious to get current date in C++
    return returnValue(buf);
  }
  XLO_FUNC_END(testToday);