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. png图片使用opacity在ie中出现黑边情况

    JQuery动画的淡入淡出效果,用在PNG24的图片上,在IE7.IE8下会出现黑边框. 有些人觉得很奇怪,为什么?潘?E6正常,反而在IE7.8下却有黑边呢. 其实问题出在filter属性上.IE6 ...

  2. 在doker上的python安装及环境部署

    python环境部署 我们今天学习的内容是如何将Django项目部署到linux服务器上,我们部署的linux系统是centos7首先,我们先在linux上搭建我们的Python3环境: 在这里首先强 ...

  3. 【java】自定义排序

    使用Comparable接口 这里定义了一个类Node,有两个属性,id,age. 排序方法是,先根据id升序排,id一样,age降序排. 里面有一个compareTo方法.返回值有三个 1. < ...

  4. 备份一下我的.bash_aliases文件

    # 这是陈悦老师的课程练习目录 alias cdchen="cd /home/branches/Documents/chen" # 每次grep都显示出行号 alias grep= ...

  5. android 数据异步加载

    public class MainActivity extends Activity { ListView listView; File cache; //访问其他线程在当前线程中存放的数据 Hand ...

  6. Activiti获取当前活动(任务)的出口(动态生成提交按钮)

    1.设置出口变量 当一个任务有一个或多个出口时,可以在出口连线出设置判断条件如图: 2.根据任务Id获取出口集合 public List<String> getOutGoingTransN ...

  7. 嵌入式平台 RAM与ROM区分

    ROM(Read Only Memory)和RAM(Random Access Memory)指的都是半导体存储器,ROM在系统停止供电的时候仍然可以保持数据,而RAM通常是在掉电之后就丢失数据,典型 ...

  8. WPF 从服务器下载文件

    1.先获取服务器下载地址,给出要下载到的目标地址 public void DownloadFileFromServer() { string serverFilePath = "http:/ ...

  9. InnoDB global status

    常见参数 Innodb_buffer_pool_pages_free 发现 Innodb_buffer_pool_pages_free 为0 ,则说明buffer_pool 已经被用光,需要增大 in ...

  10. SSD网络结构

    SSD算法,其英文全名是Single Shot MultiBox Detector. SSD的网络结构流程如下图所示:SSD总共11个block,相比较于之前的VGG16,改变了第5个block的第4 ...