C++ 我不希望Excel外接程序返回数组(相反,我需要一个UDF来更改其他单元格)

C++ 我不希望Excel外接程序返回数组(相反,我需要一个UDF来更改其他单元格),c++,arrays,excel,add-in,excel-addins,C++,Arrays,Excel,Add In,Excel Addins,我已经创建了一个Excel外接程序,该外接程序的一个功能是,假设新的年份当前需要2年,并在这2年之间的每一个新年日以Excel数组的形式输出。因此,News_years20002002将在最后一个单元格中返回2000年1月1日、2001年1月1日和2002年1月1日 问题是,我必须知道这段时间将有3个日期,选择3个单元格,在顶部单元格中输入我的公式,然后按Ctrl+Shift+enter填充数组 我使用XLW版本5将C++代码转换成.xLL文件。我真的很希望有一种方法,我可以用我的公式填充一个方

我已经创建了一个Excel外接程序,该外接程序的一个功能是,假设新的年份当前需要2年,并在这2年之间的每一个新年日以Excel数组的形式输出。因此,News_years20002002将在最后一个单元格中返回2000年1月1日、2001年1月1日和2002年1月1日

问题是,我必须知道这段时间将有3个日期,选择3个单元格,在顶部单元格中输入我的公式,然后按Ctrl+Shift+enter填充数组

我使用XLW版本5将C++代码转换成.xLL文件。我真的很希望有一种方法,我可以用我的公式填充一个方块,Excel会根据需要用适当的日期填充下面的方块。有人知道这是否可能吗?还是不可能


非常感谢

这实际上是可能的,尽管很复杂。我重新发布这件魔术,因为它坐在链接连接,如果有人可以访问

Excel严格禁止自定义项更改任何单元格、工作表、, 或工作簿属性,有一种方法可以在 在中使用Windows计时器和Application.OnTime计时器调用UDF 序列必须在UDF中使用Windows计时器,因为 Excel将忽略UDF中的任何Application.OnTime调用。但是,因为 Windows计时器有限制,如果出现错误,Excel将立即退出 如果某个单元格正在编辑或出现错误,Windows计时器将尝试运行VBA代码 对话框处于打开状态,它仅用于计划应用程序。OnTime 计时器,一个安全的计时器,Excel只允许在单元格 未被编辑且未打开任何对话框

下面的示例代码说明了如何从启动Windows计时器 在UDF中,如何使用该计时器例程启动 Application.OnTime计时器,以及如何将已知信息传递给 将UDF转换为后续计时器执行的例程。下面的代码必须是 放置在常规模块中

私有声明函数SetTimer Lib user32_ 再见,只要_ 拜瓦尔:只要_ 拜瓦尔:只要_ ByVal lpTimerFunc尽可能长_ 只要 私有声明函数KillTimer Lib user32_ 再见,只要_ 拜瓦尔·尼德事件_ 只要 专用McCalculatedCells作为集合 私人mWindowsTimerID,只要 私有MapApplicationTimerTime作为日期 公共函数AddTwoNumber_ ByVal值1为双精度_ ByVal值2作为双精度_ 加倍 '这是一个UDF,它返回两个数字的总和并启动windows计时器 '启动第二个Appliction.OnTime计时器,该计时器执行的活动不是 “在UDF中允许。不要使此UDF易失性,传递任何易失性函数 '或传递包含易失性公式/函数或 "不受控制的循环将开始。 addTwoNumber=Value1+Value2 '缓存调用方的引用,以便可以在非UDF例程中处理它 如果mCalculatedCells为Nothing,则设置mCalculatedCells=New Collection 出错时继续下一步 mCalculatedCells.Add Application.Caller,Application.Caller.Address 错误转到0 '设置/重置计时器应该是UDF中采取的最后一个操作 如果mWindowsTimerID 0,则KillTimer 0&,mWindowsTimerID mWindowsTimerID=SetTimer0&,0&,1,AfterUDFRoutine1的地址 端函数 公共子事后预测1 '这是两个计时器例程中的第一个。这一个被称为窗口 “计时器。因为如果单元格正在编辑或 '对话框打开此例程使用 'Application.OnTime,在自定义项中被忽略。 '停止Windows计时器 出错时继续下一步 KillTimer 0和,mWindowsTimerID 错误转到0 mWindowsTimerID=0 '取消以前的任何实时计时器 如果MapApplicationTimerTime为0,则 出错时继续下一步 Application.OnTime MapApplicationTimerTime,AfterUDFRoutine2,False 错误转到0 如果结束 '时间表计时器 mApplicationTimerTime=Now Application.OnTime MapApplicationTimerTime,AfterUDFRoutine2 端接头 公共次级后处理程序2 '这是两个计时器例程中的第二个。因为这个定时器程序是 '由应用程序触发。当它是安全的,即Excel将不允许 '除非环境安全,否则计时器将启动没有打开的模型对话框或单元 "正在编辑中。 暗淡单元格作为范围 '不允许在自定义项中执行任务。。。 Application.ScreenUpdating=False Application.Calculation=xlCalculationManual 当McCalculatedCells.Count>0时执行此操作 设置单元格=mCalculatedCells1 McCalculatedCells。删除1个 Cell.Offset0,1.Value=Cell.Value 环 Application.Calculation=xlCalculationAutomatic Application.ScreenUpdating=True 端接头
多亏了这个页面上的早期文章,我能够创建一种易于使用的模块



''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' POST UDF UPDATING MODULE                                   v.9.2020 cdf
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Since Excel won't allow UDFs to update any other cells,
'   an API timer is used to trigger a post UDF subroutine.
'
' This acts like a recalculate.  Your code should recalculate the entire
'   sheet.  Tried to get it to work with a specific range, but, with all
'   the different update variations ({Enter}, {Tab}, {Backspace}, {Delete},
'   mouse click in the middle of an update, etc.), no luck. Any ideas?
'
' Originally, before the slight tweak, the code was found here:
'   https://stackoverflow.com/questions/8520732/
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'                             HOW TO USE
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Create a module (in the Modules folder) and copy this entire document 
'   into it.
'
'
' Code this code into your UDF's subroutine in your module (in Modules
'   folder) (should be close to the end of the code):
'
'     ' Use Post UDF Timer to update other cells.
'     Call TimerModulesName.SetAPITimer("UDFModule.PostUDFRoutine")
'
'
' Edit the code names:
'
'     Change TimerModulesName to the module you copied this document into.
'            UDFModule        to the module your post UDF subroutine is in.
'            PostUDFRoutine   to your post UDF subroutine.
'
'     Example: Module4.SetAPITimer("Module1.UpdateMyCells")
'
'

#If VBA7 Then

Private Declare PtrSafe Function SetTimer Lib "user32" ( _
      ByVal hwnd As Long, _
      ByVal nIDEvent As Long, _
      ByVal uElapse As Long, _
      ByVal lpTimerFunc As LongLong _
   ) As Long

Private Declare PtrSafe Function KillTimer Lib "user32" ( _
      ByVal hwnd As Long, _
      ByVal nIDEvent As Long _
   ) As Long
   
#Else

Private Declare Function SetTimer Lib "user32" ( _
      ByVal HWnd As Long, _
      ByVal nIDEvent As Long, _
      ByVal uElapse As Long, _
      ByVal lpTimerFunc As Long _
   ) As Long

Private Declare Function KillTimer Lib "user32" ( _
      ByVal HWnd As Long, _
      ByVal nIDEvent As Long _
   ) As Long
   
#End If

Private mCalculatedCells As Collection
Private mWindowsTimerID As Long
Private mApplicationTimerTime As Date
Private mRoutine As String

Public Sub SetAPITimer(sRoutine As String)
    
' Starts a windows timer that starts a second Appliction.OnTime
' timer that performs activities not allowed in a UDF. Do
' not make this UDF volatile, pass any volatile functions
' to it, or pass any cells containing volatile
' formulas/functions or uncontrolled looping will start.

    ' Cache the caller's reference so it can be dealt with in a non-UDF routine
    If mCalculatedCells Is Nothing Then Set mCalculatedCells = New Collection
    On Error Resume Next
    mCalculatedCells.Add Application.Caller, Application.Caller.Address
    On Error GoTo 0

    ' Setting/resetting the timer should be the last action taken in the UDF
    If mWindowsTimerID  0 Then KillTimer 0&, mWindowsTimerID
    mWindowsTimerID = SetTimer(0&, 0&, 1, AddressOf AfterUDFRoutine1)

    ' Set Post UDF module and routine
    mRoutine = sRoutine
End Sub

Private Sub AfterUDFRoutine1()

' This is the first of two timer routines. This one is called by the Windows
' timer. Since a Windows timer cannot run code if a cell is being edited or a
' dialog is open this routine schedules a second safe timer using
' Application.OnTime which is ignored in a UDF.

   ' Stop the Windows timer
   On Error Resume Next
   KillTimer 0&, mWindowsTimerID
   On Error GoTo 0
   mWindowsTimerID = 0

   ' Cancel any previous OnTime timers
   If mApplicationTimerTime  0 Then
      On Error Resume Next
      Application.OnTime mApplicationTimerTime, "AfterUDFRoutine2", , False
      On Error GoTo 0
   End If

   ' Schedule timer
   mApplicationTimerTime = Now
   Application.OnTime mApplicationTimerTime, "AfterUDFRoutine2"
End Sub

Private Sub AfterUDFRoutine2()

' This is the second of two timer routines. Because this timer routine is
' triggered by Application.OnTime it is safe, i.e., Excel will not allow the
' timer to fire unless the environment is safe (no open model dialogs or cell
' being edited).

    ' Do tasks not allowed in a UDF... (post UDF code)
    Application.Run mRoutine
End Sub



@是的。虽然它很复杂,但它做不到的地方太多了
ften进行了大量调查。@gserg-是的,这是一种更容易实现的方法。感谢您将此技术粘贴到这里!请记住,这是遗留代码,所以在64位版本中使用它之前,请确保熟悉64位环境指针和句柄,否则可能会使Excel崩溃。PtrSafe和LongPtr是必须的,可能需要进行其他更改。如果用户在运行AfterUDFRoutine1时开始编辑单元格,会发生什么情况?您可以尝试演示如何不受限制地使用UDF。