问题描述
我正在寻找一种方法来确定我的 XLL 内部调用是来自重新计算过程还是来自为单元格输入的新公式。我已经看到 XLL 可以检测它是否被函数向导调用(通过检查窗口类等)的例子,但是如果它直接输入到单元格中呢?
XLOPER xlRef;
Excel(xlfCaller,&xlRef,0);
但这并没有让我走得很远。我试图模仿 Excel 对 TODAY() 函数的处理,如果直接在单元格中输入公式(而不是粘贴或从另一个函数中调用),它会更改单元格编号格式。
解决方法
可以通过挂钩 SheetChange 事件来复制 TODAY() 行为的这一方面 - 这只会在输入公式时触发,而不会在重新计算时触发(即使使用 Ctrl-Alt-F9)。我不知道 TODAY() 是否使用这种方法,或者它可能使用了用户定义函数不可用的东西。此外,复制 TODAY() 需要解析公式并应用一些逻辑来确定它是否应用日期格式,这会有点棘手,但有一些 Excel 公式解析器。
在 xlOil 中(免责声明:我写的)它可以实现为:
XLO_FUNC_START(testToday())
{
CallerInfo caller;
if (!caller.fullSheetName().empty()) // Check caller is worksheet
{
// Add a SheetChange handler
auto handle = xloil::Event::SheetChange().bind(
[=](const wchar_t* wsName,const Range& target)
{
// Need to check range here as well to avoid being triggered by another sheet change
if (wsName == caller.sheetName())
excelApp().Range[caller.writeAddress().c_str()]->NumberFormat = L"dd-mm-yyyy";
}
);
// Wait 0.5 sec then unbind the event handler by queuing a window message with Excel
auto milliSecsDelay = 500;
excelPost([=]() mutable
{
handle.reset(); // Removes the SheetChange handler
},QueueType::WINDOW,milliSecsDelay);
}
// This is how to get the current date in C++
std::tm buf;
auto now = std::time(0);
localtime_s(&buf,&now);
return returnValue(buf); // xlOil will convert the std::tm to an Excel date
}
XLO_FUNC_END(testToday);
这只是一个概念验证,可以做一些整理,例如应该检查范围,如果多次调用该函数,开销可能会很大。