Pat*_*ard 4 .net c# multithreading timer
我想IMessageFilter在Excel Addin 上启用我必须写入excel.我从这里举了一些例子说:
消息过滤器是每个线程,所以我们将此线程注册为消息过滤器(不是创建加载项的主线程 - 因为这是Excel的主线程
我的问题是,当一个计时器过去导致从ThreadPool线程调用写入方法时,我的系统写入excel ,因为它IMessageFilter不能访问RetryRejectedCall部分IMessageFilter,因为它存在于调用者线程而不是执行的生成者之间.计时器.
所以,我的问题是:有没有办法可以强制计时器的Elapsed事件在初始化计时器的同一个线程上运行?
编辑:
我的问题是,如何IMessageFilter在抛出拒绝/忙碌时捕获excel错误?
谢谢
您可以使用Timer.SynchronizingObjectproperty来封送在间隔过去时发出的事件处理程序调用.
这是来自MSDN:
当Elapsed事件由可视Windows窗体组件(如按钮)处理时,通过系统线程池访问组件可能会导致异常或者可能无法正常工作.通过将SynchronizingObject设置为Windows窗体组件来避免此影响,这会导致处理Elapsed事件的方法在创建组件的同一线程上调用.
假设您正在使用WinFrom,并且您正在从主窗体中创建计时器实例:
System.Timers.Timer t = new System.Timers.Timer();
t.SynchronizingObject = this;
t.Elapsed += t_Elapsed;
t.Start();
Run Code Online (Sandbox Code Playgroud)
完整答案如下:
问题:将数据写入 Excel 的类无法处理来自 Excel 的“忙/拒绝”响应消息。
解决方案:按照此处IMessageFilter所述实现接口
IMessageFilter定义(来自链接):
namespace ExcelAddinMessageFilter
{
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct INTERFACEINFO
{
[MarshalAs(UnmanagedType.IUnknown)]
public object punk;
public Guid iid;
public ushort wMethod;
}
[ComImport, ComConversionLoss, InterfaceType((short)1),
Guid("00000016-0000-0000-C000-000000000046")]
public interface IMessageFilter
{
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
int HandleInComingCall([In] uint dwCallType, [In] IntPtr htaskCaller,
[In] uint dwTickCount,
[In, MarshalAs(UnmanagedType.LPArray)] INTERFACEINFO[]
lpInterfaceInfo);
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
int RetryRejectedCall([In] IntPtr htaskCallee, [In] uint dwTickCount,
[In] uint dwRejectType);
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
int MessagePending([In] IntPtr htaskCallee, [In] uint dwTickCount,
[In] uint dwPendingType);
}
}
Run Code Online (Sandbox Code Playgroud)
IMessageFilter我的课程的实现部分(参见链接):
#region IMessageFilter Members
int ExcelAddinMessageFilter.IMessageFilter.
HandleInComingCall(uint dwCallType, IntPtr htaskCaller, uint dwTickCount, ExcelAddinMessageFilter.INTERFACEINFO[] lpInterfaceInfo)
{
// We're the client, so we won't get HandleInComingCall calls.
return 1;
}
int ExcelAddinMessageFilter.IMessageFilter.
RetryRejectedCall(IntPtr htaskCallee, uint dwTickCount, uint dwRejectType)
{
// The client will get RetryRejectedCall calls when the main Excel
// thread is blocked. We can handle this by attempting to retry
// the operation. This will continue to fail so long as Excel is
// blocked.
// As an alternative to simply retrying, we could put up
// a dialog telling the user to close the other dialog (and the
// new one) in order to continue - or to tell us if they want to
// abandon this call
// Expected return values:
// -1: The call should be canceled. COM then returns RPC_E_CALL_REJECTED from the original method call.
// Value >= 0 and <100: The call is to be retried immediately.
// Value >= 100: COM will wait for this many milliseconds and then retry the call.
return 1;
}
int ExcelAddinMessageFilter.IMessageFilter.
MessagePending(IntPtr htaskCallee, uint dwTickCount, uint dwPendingType)
{
return 1;
}
#endregion
Run Code Online (Sandbox Code Playgroud)
定义和实现接口后IMessageFilter,我设置了 STAThread和 a,Timers.Timer如下所示:
线:
thread = new Thread(WriteToExcel);
thread.SetApartmentState(ApartmentState.STA);
Run Code Online (Sandbox Code Playgroud)
定时器:
timer = new System.Timers.Timer();
timer.Interval = 2000;
timer.Elapsed += new ElapsedEventHandler(StartSTAThread_Handler);
Run Code Online (Sandbox Code Playgroud)
其中StartSTAThread_Handler定义为:
void StartSTAThread_Handler(object source, ElapsedEventArgs e)
{
thread.Start();
thread.Join();
thread = null;
}
Run Code Online (Sandbox Code Playgroud)
该线程调用我用来写入 Excel 的方法,并使用IMessageFilter上述接口处理拒绝的消息。我要做的最后一件事是完全限定 excel OM 引用,即;代替:
Excel.Range rng = app.ActiveSheet.Range["range_name"];
rng.Copy(); // ERRROR: message filter's RetryRejectedCall is NOT called
Run Code Online (Sandbox Code Playgroud)
我必须使用完全限定的引用:
app.ActiveSheet.Range["range_name"].Copy // OK: calls RetryRejectedCall when excel dialog etc is showing
Run Code Online (Sandbox Code Playgroud)
虽然这似乎适合我的需要,但它似乎确实与另一张海报所描述的“两点规则”相矛盾......