首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何从xll调用xlcOnTime

如何从xll调用xlcOnTime
EN

Stack Overflow用户
提问于 2016-03-31 03:19:25
回答 2查看 274关注 0票数 2

基本上是尝试在C++ I don't want my Excel Add-In to return an array (instead I need a UDF to change other cells)中复制以下VBA代码,但在系统计时器函数中对Excel4(xlcOnTime,&timer2,2,&now,cmd)的调用返回代码为2,即无法设置Excel的计时器。有什么想法吗?我正在尝试将我的外接程序限制为1,并且使用c++代码。我可以通过两个插件来解决这个问题,一个在C++中,另一个在VBA中,但我不愿意这样做。

代码语言:javascript
复制
namespace {
  UINT timer1 = 0;
  XLOPER timer2;
  XLOPER now;
};

//
//this function is xlfRegister as ApplicationOnTime
//
int __stdcall application_on_time()
{
  XLOPER ret;
  XLOPER ref;
  XLOPER value;
  //define the destination cells to be changed
  ref.xltype = xltypeSRef;
  ref.val.sref.count = 1;
  ref.val.sref.ref.rwFirst = 10;
  ref.val.sref.ref.rwLast = 12;
  ref.val.sref.ref.colFirst = 10;
  ref.val.sref.ref.colLast = 20;

  //the values
  value.xltype = xltypeMulti;
  value.val.array.columns = 2;
  value.val.array.rows = 3;
  value.val.array.lparray = new XLOPER[6];
  (value.val.array.lparray[0]).xltype = xltypeNum;
  (value.val.array.lparray[0]).val.num = 9991;
  (value.val.array.lparray[1]).xltype = xltypeNum;
  (value.val.array.lparray[1]).val.num = 9992;
  (value.val.array.lparray[2]).xltype = xltypeNum;
  (value.val.array.lparray[2]).val.num = 9993;
  (value.val.array.lparray[3]).xltype = xltypeNum;
  (value.val.array.lparray[3]).val.num = 9994;
  (value.val.array.lparray[4]).xltype = xltypeNum;
  (value.val.array.lparray[4]).val.num = 9995;
  (value.val.array.lparray[5]).xltype = xltypeNum;
  (value.val.array.lparray[5]).val.num = 9996;

  //set the value to the cell
  int xlret = Excel4(xlSet, &ret, 2, &ref, &value);

  printf("xlret is %d", xlret);

  return 0;
}

//xlfRegister as a command TestUserCommand, to be
//called from a button on Excel, with VBA code
//Application.run("TestUserCommand")
int __stdcall test_user_command()
{
  LPXLOPER now = new XLOPER;
  LPXLOPER cmd = new XLOPER;
  cmd->xltype = xltypeStr;
  cmd->val.str = XLUtil::MakeExcelString("ApplicationOnTime");

  Excel4(xlfNow, now, 0, NULL);

  timer2.xltype = xltypeInt;
  timer2.val.num = 0;
  int xlret = Excel4(xlcOnTime, &timer3, 2, now, cmd);
  //xlret is 0, the ApplicationOnTime command would be triggered
  //and the cells K11:U13 value get set as expected
  printf("xlret is %d", xlret);
  return 0;
}

//xlfRegister as a function TestUserFunction, to be
//called from a cell formula on Excel
//=TestUserFunction(1)
char * __stdcall test_user_function(xloper *pxl)
{
  static bool first = true;
  if (first) {
    timer2.xltype = xltypeInt;
    timer2.val.num = 0;
    first = false;
  }

  if (timer1 > 0)
  {
    UINT tmp = timer1;
    timer1 = 0;
    KillTimer(NULL, tmp);
  }

  Excel4(xlfNow, &now, 0, NULL);

  //set the system timer to triggers the MyTimerProc,
  //and MyTimerProc is triggered successfully but no luck
  //in setting the second timer that is excel
  //inside MyTimerProc
  timer1 = SetTimer(NULL, 0, 1, (TIMERPROC)MyTimerProc);

  return 0;
}

//this is the procedure referred to in the SetTimer call
void CALLBACK MyTimerProc(HWND hwnd, UINT message, UINT idTimer, DWORD dwTime)
{
  if (timer1 > 0)
  {
    UINT tmp = timer1;
    timer1 = 0;
    KillTimer(NULL, tmp);
  }
  LPXLOPER12 cmd = new XLOPER12;
  cmd->xltype = xltypeStr;
  cmd->val.str = (XCHAR *)XLUtil::MakeExcelString("ApplicationOnTime");
  now.val.num = now.val.num + 10.0 / (60.0 * 60.0 * 24.0);
  int xlret = Excel4(xlcOnTime, &timer2, 2, &now, cmd);
  //xlret is 2, indicates invalid function, no luck. the ApplicationOnTime
  //command won't be triggered

  //try to call the application_on_time function to set the values to cell
  //to no effect
  application_on_time();

}
EN

回答 2

Stack Overflow用户

发布于 2018-11-09 00:16:02

问题是,您的C++代码并不完全等同于另一个问题中的VBA代码。在VBA中通过Excel计时器运行命令

代码语言:javascript
复制
Application.OnTime

它使用Excel OnTime自动化调用。在C++中,你有

代码语言:javascript
复制
Excel4(xlcOnTime, &timer2, 2, &now, cmd);

它是XLL接口函数xlcOnTime。Excel对XLL函数调用有非常严格的限制;它们只能在特定的上下文中调用。例如,xlcOnTime可以从用户定义的Excel命令调用,但不能从Windows计时器回调调用。

您需要做的是在C++中使用完全等效的VBA代码,这意味着在C++中使用自动化。MSDN和其他资源提供了几个示例,说明如何在C++中对Excel使用自动化。他们经常使用AutoWrap函数来调用自动化,所以你需要类似这样的东西

代码语言:javascript
复制
AutoWrap(DISPATCH_METHOD, &result, pXlApp, L"OnTime", 1, COleVariant("ApplicationOnTime"));

自动化调用没有与xlc函数相同的限制,因此从Windows计时器回调发出的此类调用将被Excel接受,并运行您的ApplicationOnTime命令。

票数 1
EN

Stack Overflow用户

发布于 2016-08-10 20:12:11

我很确定原因是您不能从调用线程以外的线程调用任何Excel4函数。因为您是从TIMERPROC内部回调的,所以您可能处于事件线程或其他时间线程中。诚然,这是一个巨大的痛苦,但这就是它的方式。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36317809

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档