COM组件的线程模型与Excel多线程的背景知识

COM组件的线程模型被称之为Apartment模型,COM对象初始化时其执行上下文(Execution Context),他要么和单个线程关联STA(Single Thread Apartment ) 要么和多个线程关联MTA(Multi Thread Apartment)。Excel是一种STA线程的应用程序,使用多线程直接怼会出问题,必须借助线程的同步上下文实现线程间的消息传递。

1、Excel 开发中与线程相关的若干问题参考这个链接:

https://www.cnblogs.com/yangecnu/p/Some-Thread-Releated-Problems-and-Solutions-in-Excel-Development.html

2、SynchronizationContext的实现参考这个链接(共3篇文章,进入链接后可以找到下一章的链接):

https://www.codeproject.com/Articles/31971/Understanding-SynchronizationContext-Part-I

3、ExcelDNA是什么

Excel-DNA is an independent project to integrate .NET into Excel. With Excel-DNA you can make native (.xll) add-ins for Excel using C#, Visual Basic.NET or F#, providing high-performance user-defined functions (UDFs), custom ribbon interfaces and more. Your entire add-in can be packed into a single .xll file requiring no installation or registration.

https://excel-dna.net/

4、ExcelDNA下实现一个自定义的SynchronizationContext

https://groups.google.com/forum/#!searchin/exceldna/synchronizationcontext%7Csort:date/exceldna/pyybn0lSP8k/3DW6NOekCgAJ

ExcelDNA中的解决方案

  dynamic app;
dynamic worksheet; public void Test(IRibbonControl ribbonControl)
{
app = ExcelDnaUtil.Application;
worksheet = app.ActiveSheet;
worksheet.Cells[, ].Value = Thread.CurrentThread.ManagedThreadId;
Action<object> action = Run;
Task task = new Task(action,ExcelSynchronizationContext.Current);
task.Start(); }
private void Run(object context)
{
worksheet.Cells[, ].Value = Thread.CurrentThread.ManagedThreadId; for (int i = ; i < ; i++)
{
Thread.Sleep();
ExcelAsyncUtil.QueueAsMacro(UpdateUI, i);
}
} private void UpdateUI(object state)
{
int i = (int)state + ;
worksheet.Cells[i, ].Value = i;
worksheet.Cells[i, ].Value = Thread.CurrentThread.ManagedThreadId;
}
 Task task = new Task(action,ExcelSynchronizationContext.Current);

ExcelSynchronizationContext.Current为主线程的SynchronizationContext。
 ExcelAsyncUtil.QueueAsMacro(UpdateUI, i);

其实是执行了SynchronizationContext的Post方法。

上面是ExcelDNA里集成的SynchronizationContext实现,有兴趣可以→

尝试实现自定义一个SynchronizationContext
一个SendOrPostCallbackItem实例为一组SendOrPostCallback委托与方法、参数
 internal enum ExecutionType
{
Post,
Send
}
internal class SendOrPostCallbackItem
{
object state;
ExecutionType executionType;
SendOrPostCallback callbackMethod; internal SendOrPostCallbackItem(SendOrPostCallback callback, object state, ExecutionType executionType)
{
this.callbackMethod = callback;
this.state = state;
this.executionType = executionType;
} internal void Execute()
{
if (executionType == ExecutionType.Post)
Post();
else
Send();
}
internal void Send()
{
throw new NotImplementedException();
} internal void Post()
{
callbackMethod(state);
}
}
DiyExcelSynchronizationContext,在ExcelDNA下实现一个SynchronizationContext
 public class DiyExcelSynchronizationContext : SynchronizationContext
{
private const string RunMacroName = "ExcelSyncContext.Run";
private static readonly ConcurrentQueue<SendOrPostCallbackItem> queue = new
ConcurrentQueue<SendOrPostCallbackItem>();
private static readonly TimeSpan BackoffTime = TimeSpan.FromSeconds();
[ExcelCommand(Name = RunMacroName)]
public static void Run()
{
while (true)
{
SendOrPostCallbackItem workItem;
if (!queue.TryDequeue(out workItem))
{
return;
}
workItem.Execute();
}
}
dynamic application = ExcelDnaUtil.Application;
public override void Post(SendOrPostCallback d, object state)
{ SendOrPostCallbackItem item = new SendOrPostCallbackItem(d, state, ExecutionType.Post);
queue.Enqueue(item);
Task.Factory.StartNew(() =>
{
while (true)
{
try
{
application.Run(RunMacroName);
break;
}
catch (COMException e1)
{
if (IsRetry(e1))
{
Thread.Sleep(BackoffTime);
continue;
}
return;
}
catch (Exception e2)
{
return;
}
} });
}
public const uint RPC_E_SERVERCALL_RETRYLATER = 0x8001010A;
public const uint RPC_E_CANTCALLOUT_INASYNCCALL = 0x800AC472; public static bool IsRetry(COMException e)
{
var errorCode = (uint)e.ErrorCode;
switch (errorCode)
{
case RPC_E_SERVERCALL_RETRYLATER:
case RPC_E_CANTCALLOUT_INASYNCCALL:
return true;
default:
return false;
}
}
}
 

Excel的线程 与 SynchronizationContext的实现的更多相关文章

  1. 浅谈Excel开发:十 Excel 开发中与线程相关的若干问题

    采用VSTO或者Shared Add-in等技术开发Excel插件,其实是在与Excel提供的API在打交道,Excel本身的组件大多数都是COM组件,也就是说通过Excel PIA来与COM进行交互 ...

  2. 利用SynchronizationContext.Current在线程间同步上下文

    简而言之就是允许一个线程和另外一个线程进行通讯,SynchronizationContext在通讯中充当传输者的角色.另外这里有个地方需要清楚的,不是每个线程都附加SynchronizationCon ...

  3. 利用SynchronizationContext.Current在线程间同步上下文(转)

    https://blog.csdn.net/iloli/article/details/16859605 简而言之就是允许一个线程和另外一个线程进行通讯,SynchronizationContext在 ...

  4. 浅谈Excel开发:六 Excel 异步自定义函数

    上文介绍了Excel中的自定义函数(UDF ),它极大地扩展了Excel插件的功能,使得我们可以将业务逻辑以Excel函数的形式表示,并可以根据这些细粒度的自定义函数,构建各种复杂的分析报表. 普通的 ...

  5. 搞懂 SynchronizationContext(第一部分)【翻译】

    SynchronizationContext -MSDN 很让人失望 我不知道为什么,目前在.Net下关于这个类只有很少的资料.MSDN文档也只有很少的关于如何使用SynchronizationCon ...

  6. 搞懂 SynchronizationContext

    SynchronizationContext -MSDN 很让人失望 我不知道为什么,目前在.Net下关于这个类只有很少的资料.MSDN文档也只有很少的关于如何使用SynchronizationCon ...

  7. await之后的线程问题

    之前看了园子里的一篇文章「async & await的前世今生」,收益颇多.而其中有句话被博主特意用红色标注,所以留意多看了几眼,「await 之后不会开启新的线程(await 从来不会开启新 ...

  8. 重新想象 Windows 8 Store Apps (48) - 多线程之其他辅助类: SpinWait, SpinLock, Volatile, SynchronizationContext, CoreDispatcher, ThreadLocal, ThreadStaticAttribute

    [源码下载] 重新想象 Windows 8 Store Apps (48) - 多线程之其他辅助类: SpinWait, SpinLock, Volatile, SynchronizationCont ...

  9. C# Winform 跨线程更新UI控件常用方法汇总(多线程访问UI控件)

    概述 C#Winform编程中,跨线程直接更新UI控件的做法是不正确的,会时常出现“线程间操作无效: 从不是创建控件的线程访问它”的异常.处理跨线程更新Winform UI控件常用的方法有4种:1. ...

随机推荐

  1. jsp页面间的传值方法

    JSP页面间传递参数是经常需要使用到的功能,有时还需要多个JSP页面间传递参数.下面介绍一下实现的方法. (1)直接在URL请求后添加 如:< a href="thexuan.jsp? ...

  2. 深入了解line-height(各种单位总结1.5/150%/1.5em)

    默认状态,浏览器使用1.0-1.2 line-height, 这是一个初始值.你可以定义line-height属性来覆盖初始值:p{line-height:140%} 你可以有5种方式来定义line- ...

  3. shell编程:有类型的变量

    1.通过 declare 和 typeset 命令 declare 和 typeset 两者等价 declare 和 typeset 都是用来定义变量类型的 下面以 declare 进行总结 2.de ...

  4. java性能调优03

    1.java中的四种引用类型(级别由高到低为:强引用,软引用,弱引用和虚引用) 1.1 强引用:默认创建的变量都是强引用,垃圾回收机制不会将其回收,当内存空 间不足,Java虚拟机宁愿抛出OutOfM ...

  5. List、Map、Set三个接口存取元素时,各有什么特点

    List接口以特定索引来存取元素,可以有重复元素 Set接口不可以存放重复元素(使用equals方法区分是否重复) Map接口保存的是键值对(key-value-pair)映射,映射关系可以是一对一或 ...

  6. 算法竞赛模板 动态规划之背包DP

    ① 01背包 有n件物品和一个容量为v的背包.第i件物品的价值是c[i],体积是w[i].求解将哪些物品装入背包可使价值总和最大. 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放. ...

  7. Oracle如何杀同库不同实例的会话

    今天处理了一个生产上的问题,主要就是杀会话, 生产环境是Oracle11gR2 RAC:有同事开发报表,报表工具连接到数据库上特别嚣张,把内存pin住: Select s.INST_ID, s.Mac ...

  8. C# 连接Excel,获取表格数据,获取多个sheet中的数据,获取多个sheet名

    /// <summary> /// 获取Excel内容. /// </summary> /// <param name="sheetName"> ...

  9. PHP-删除排序数组中的重复项

    给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成. 示例 1 ...

  10. rest framework之视图组件

    一.APIView  APIView继承的是和django中CBV模式下的View类.View类中的dispatch方法通过反射对不同的请求方法执行不同的函数.而APIView不仅拥有这个特性,而且重 ...