ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 4568|回复: 12

Excel Com插件异常问题处理-Excel中的线程同步

[复制链接]

TA的精华主题

TA的得分主题

发表于 2015-4-20 20:45 | 显示全部楼层 |阅读模式



Excel Com插件异常问题处理-Excel中的线程同步

Excel中的线程同步
    前面讲过STA以及SynchronizationContext,这是因为Excel也是一种STA线程的应用程序,寄宿在Excel之上

的Automation程序也是STA的,了解这一点非常重要。

   通常在Excel的插件开发中,我们的业务逻辑可能比较复杂,这些复杂的计算一般不应该放到Excel的主UI线

程中,我们需要新建工作线程,然后在里面进行计算。获得了结果之后,我们应该在回到Excel的UI线程中去更

新界面。但是我们采用.NET技术开发Excel的Automation有一个特殊性在于,我们可以直接在非UI线程中去调用

Excel的COM对象,在正常情况下,如果Excel比较空闲,没有任何问题,但是如果Excel此时比较忙,就会抛出

COM异常,这种异常难以捕捉。这也是导致插件不稳定的一个非常重要的因素。这种情况通常出现在以下情形中



当我们的插件在后台线程中向服务端请求了大量数据,进行了一些处理(这种情况很常见)后,在Excel的Sheet页

中将数据填充到单元格中,然后对单元格进行样式,字体等格式化,这个过程需要与COM进行交互,而且在某些

情况下比较耗时,如果在此过程中,用户操作了Excel的单元格,比如鼠标点击填充过程中的单元格,这样由于

后台线程通过COM对象对Excel的操作会遇到忙碌状态,就会抛出COM异常。
在RTD 函数中,我们在某些情况下需要定时刷新单元格,比如在Excel中直播NBA比赛得分,使用实时的股票市场

行情信息进行建模。在RTD 中,我们可以直接调用UpdateNotify方法,通常该方法应该在UI主线程上调用,这样

Excel就会将其放到消息队列中,在某一时候触发。但是在很多时候,我们获取数据比如NBA实时比分,实时行情

数据,通常是在另外一根工作线程中进行的,我们可以在工作线程中直接调用RTD的UpdateNofity方法,但是在

Excel忙碌的时候就会抛出COM异常。
    Excel中运行我们再工作线程中通过Excel 的Application对象来直接更新UI界面元素给了我们一个假象。原

因在于这样是很不稳定的,非Excel主线程的每一次COM调用中都需要检查是否抛出异常,在调用过程中Excel很

可能处于忙碌状态,Excel也可能在任何情况下拒绝线程对COM调用的请求,尤其是在用户正与Excel进行交互的

时候。通常我们至少要捕获和处理一下三种COM异常:

u const uint RPC_E_SERVERCALL_RETRYLATER = 0x8001010A;
u const uint VBA_E_IGNORE = 0x800AC472;
u const uint RPC_E_CALLREJECTED
     在其他线程中直接调用Excel对象不仅会导致性能损失,而且会增加插件的复杂性和不稳定性。

    正确的做法是,在工作线程中获取Excel主线程对象的SynchronizationContext,然后将待操作的步骤Post

到Excel主线程的消息队列中等待处理。但是作为一个Addin,在一般情况下如果直接获取

SynchronizationContext对象,该对象是为空的,只有在插件加载后,手动创建一个Winform窗体或者控件才能

够获取到主线程的SynchronizaitonContext对象。这个From窗体通常就是我们插件的登录窗体。

    比如如果要在非Excel 主线程中调用RTD函数的UpdateNotify方法,我们可以首先定义一个

SynchronizationContext用来保存Excel主线程的同步上下文。

private SynchronizationContext ExcelContext;
    然后在RTD启动时获取当前Excel主线程的上下文。

public int ServerStart(IRTDUpdateEvent CallbackObject)
{
    this.ExcelContext = new SynchronizationContext();
    xlRTDUpdater = CallbackObject;
}
   最后工作线程中,通过传进来的ExcelContext,然后将需要做的操作Send或者Post回Excel主线程中执行。

ExcelContext.Post(delegate(object obj)
            {
                xlRTDUpdater.UpdateNotify();
            }, null);
  所以其他非UI线程中需要操作Excel COM对象的方法经过如此封装将需要做的操作以消息的形式封送到UI线程

,这样就可以解决之前调用COM组件可能出现的COM异常,能够极大提高Excel插件的稳定性。

    本文很多内容涉及到COM组件的相关知识,这里只是简单的讲解了一些与Excel插件开发中可能与之相关的一

些问题,介绍了如何正确的在工作线程中更新Excel UI操作的一些正确做法,希望这些知识对您有所帮助。

TA的精华主题

TA的得分主题

发表于 2015-5-24 22:23 | 显示全部楼层
请教,我现在就碰到工作线程无法访问工作表、单元格对象的问题。看以上文字能明白为什么会这样。但,还是不懂如何去处理。 那个主线程对象也是看的一知半解。实践中,要如何处理这种冲突。让工作线程也能正常访问或者说使用工作表、单元格等对象

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-5-24 22:51 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
yfzdb 发表于 2015-5-24 22:23
请教,我现在就碰到工作线程无法访问工作表、单元格对象的问题。看以上文字能明白为什么会这样。但,还是不 ...

最笨的方法是反复try

TA的精华主题

TA的得分主题

发表于 2015-5-25 00:52 | 显示全部楼层
不行啊,实际上,主线程早已结束操作。至少我能确定,工作线程在操作工作表对象时,主线程已经结束运行了。

TA的精华主题

TA的得分主题

发表于 2015-6-16 17:40 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2016-10-29 12:16 | 显示全部楼层
我现在的程序就是进行计算的时候就没响应了,而如果到处加入doevent的话,程序效率会大幅下跌,请教下老师,我该如何是好,最简便的方法是什么呢?
只要能运行的时候,不影响我选择和查看表格内容即可,如果功能上可能的话,最好能实现我在vba程序运行时点击选择单元格时的自定义功能

TA的精华主题

TA的得分主题

 楼主| 发表于 2016-10-29 12:18 | 显示全部楼层
KeepingO 发表于 2016-10-29 12:16
我现在的程序就是进行计算的时候就没响应了,而如果到处加入doevent的话,程序效率会大幅下跌,请教下老师,我 ...

如果在代码工作的时候不想干扰到excel,一般是采用异步UDF或者RTD技术

TA的精华主题

TA的得分主题

发表于 2016-10-29 12:19 | 显示全部楼层
liucqa 发表于 2016-10-29 12:18
如果在代码工作的时候不想干扰到excel,一般是采用异步UDF或者RTD技术

感谢老师回复,请教下有没有入门的资料可以学习推荐的?

TA的精华主题

TA的得分主题

 楼主| 发表于 2016-10-29 12:22 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
KeepingO 发表于 2016-10-29 12:19
感谢老师回复,请教下有没有入门的资料可以学习推荐的?

vba是不行的,如果你打算学习C#的话,可以考虑

http://www.cnblogs.com/yangecnu/ ... efine-Function.html

TA的精华主题

TA的得分主题

发表于 2016-10-29 12:36 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
liucqa 发表于 2016-10-29 12:18
如果在代码工作的时候不想干扰到excel,一般是采用异步UDF或者RTD技术

再请教下老师,从这两个实现的方法来看,哪一种较为简单呢?
刚才去搜索了一下rtd相关文档,貌似需要用c++来开发,然后还有什么com组件注册之类的,实现起来需要深厚的功力
自己c语言的水平还停留在学校课本一档,并未实际开发过具体项目,现在一直学习vba自己使用中
如果我只是简单的想要类似两个线程,一个主线程实现数据的定时自动计算更新,另一个供我能查看上步骤刷新后的数据即可,选择哪个研究起来比较简单易行呢?
还望老师给点意见,谢谢
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2025-1-12 17:35 , Processed in 0.030162 second(s), 8 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表