Excel开发
浅谈Excel开发:九 Excel 开发中遇到的常见问题及解决方法
Excel开发过程中有时候会遇到各种奇怪的问题,下面就列出一些本人在开发中遇到的一些比较典型的问题,并给出了解决方法,希望对大家有所帮助。
一 插件调试不了以及错误导致崩溃的问题
在开发机器上,有时可能会装有多个版本的.NET运行时,有时候也可能装有多个版本的Visual Studio,本人的开发机器上就安装了3个版本的Visual Studio,在最新的Visual Studio 2013出来之后,就迫不及待的把工程文件迁移到2013上来了,但是在设置了启动程序之后,调试的时候,断点根本不能命中,也调试不进去。即使使用Attached to process方式也不行。
该问题是由于在安装有多个.NET版本的机器上,由于某些原因,会导致Excel不知道为Com Add-in加载哪个版本的Framework导致的。注:这里仅针对是用.NET技术开发Shared Add-in插件的情况,由于VSTO 中的安装部署文件.vsto中注明了程序集的版本,所以不存在该问题。
解决方法是新建一个名为EXCEL.EXE.config的配置文件,放到和EXCEL.EXE同级的目录下,配置如下,在startup节点下新建supprotedRuntime节点,指定运行时的版本号,即可解决该问题:
在Shared Add-in插件开发的初期,在测试机器上测试的时候,有时会由于代码错误,导致Excel直接崩溃掉的问题。在开发机器上,我们只需要将在该配置文件中,将runtime节点下的legacyUnhandledExceptionPolicy的Enable属性设置为true,这样,Excel在出现问题的时候就会弹出提示框,有助于帮助查找错误出现的原因。
这其实也是相较于VSTO,Shared Add-in应用程序的缺点之一,VSTO的一个插件是加载到各自的App Domain中的,出现问题不会影响其他的插件。
二 若干Excel方法调用会导致出错
由于需要兼容不同版本的Excel,但是随着版本的变化,Excel暴漏出来的API方法的参数也会发生变化。有时候采用直接调用的方式在遇到版本不同时会抛出异常,这种COM类型的异常一般很难处理和恢复。在有些时候,通过采用“晚绑定”的方式,采用反射调用方法就可以解决这一问题。
以条件着色功能为例。在使用插件获取并输出数据的时候,通常需要根据条件对单元格进行着色,比如,输出股票的涨跌和涨跌幅的时候,人们一般习惯将涨的标注为红色,跌的标注为绿色。Excel中对Range进行单元格条件可以使用FormatCoondition对象,该对象有如下方法,以添加涨跌幅的条件着色为例,代码如下。
object missing = Type.Missing;
FormatCondition conditionFall = (FormatCondition)tmpRange.FormatConditions.Add(XlFormatConditionType.xlCellValue, XlFormatConditionOperator.xlLess, "=0", missing);
conditionFall.Font.ColorIndex = 10;//Green FormatCondition conditionRise = (FormatCondition)tmpRange.FormatConditions.Add(XlFormatConditionType.xlCellValue, XlFormatConditionOperator.xlGreater, "=0", missing);
conditionRise.Font.ColorIndex = 3;//Green
该方法在Excel07及以上版本中没有问题,但是在03下就会抛出异常。由于个版本的API中,参数个数不一样。所以采用反射的方法,将参数以数组的方式传入即可解决该问题。
下面这个方法封装了FoormationCoondition的Add方法。
/// <summary>
///兼容Excel 2003-Excel2010的代码条件着色,如果直接使用FormatConditions.Add方法,则不能兼容
///详情可以参考:http://social.msdn.microsoft.com/Forums/en-US/vsto/thread/8a91d154-f766-427a-963c-16dfa39e154a
///使用方法如: tempRange.AddConditionValue(XlFormatConditionOperator.xlLess, "=0");
/// </summary>
/// <param name="R">待进行条件着色的Range区域</param>
/// <param name="ConditionOperator">找色条件,如,大于,小于</param>
/// <param name="Formula">具体的值</param>
/// <returns></returns>
public static FormatCondition AddConditionValue(Range R, XlFormatConditionOperator ConditionOperator, string Formula)
{
return (FormatCondition)R.FormatConditions.GetType().InvokeMember("Add", BindingFlags.InvokeMethod, null, (object)R.FormatConditions, new object[] { XlFormatConditionType.xlCellValue, ConditionOperator, Formula });
}
使用该方法,上面的代码改写为:
FormatCondition conditionFall = AddConditionValue(tempRange, XlFormatConditionOperator.xlLess, "=0");
conditionFall.Font.ColorIndex = 10;//Green FormatCondition conditionRise = AddConditionValue(tempRange, XlFormatConditionOperator.xlGreater, "=0");
conditionRise.Font.ColorIndex = 3;//Red
Excel中遇到同一方法由于不同API版本参数不同导致出现问题,都可以采取上面的采用反射方法调用来解决问题。
三 Excel自定义函数中包含.xla或者.xll文件路径的问题
一般地通常的插件都会开发相应的自定义函数 (UDF),除了使用C#类库编写自定义函数,大部分都是将自定义函数写在Excel的.xla或者xll文件中,有时候也会使用自定义函数编写一些标准的模板供用户调用。当这些模板中包含有自定义函数,当用户将该模板保存到其他位置之后,再次打开,这些单元格中的函数就会包含.xla或者.xll的路径。比如"C:\Program Files\Installation folder\MyUDFs.xla!MyUDF"等,原因是Excel在内部会包含自定义函数文件的完整路径。
这会导致一些问题,比如说,改自定义函数不能够正确的执行,不能求值等等。
就解决方法就是在vba中,在SheetOpen事件中,将所有包含函数的路径进行重新定向到系统指标的自定义函数类库的目录下即可。VBA代码如下,主要的方法为_Workbook.ChangeLink 方法,VBA的代码如下。将该部分代码写到vba类库中即可。
Private Sub ExcelApp_WorkbookOpen(ByVal Wb As Workbook)
ReLink Wb
End Sub Public Sub ReLink(ByVal oBook As Workbook)
If IsEmpty(oBook.LinkSources(xlLinkTypeExcelLinks)) Then Exit Sub Dim lk As Variant For Each lk In oBook.LinkSources(xlLinkTypeExcelLinks)
If lk Like "*" & ThisWorkbook.Name And lk <> ThisWorkbook.FullName Then
oBook.ChangeLink lk, ThisWorkbook.FullName, xlLinkTypeExcelLinks
End If
Next lk
End Sub
四 自定义函数加载的问题
还是UDF加载的问题,如果是采用.xla或者xll承载自定义函数的话,在插件启动的时候需要加载改文件到Excel中,这样Excel才能够使用这里面的自定义函数,并在Excel 2007及以上版本中会给出函数的智能提示。
一般地,在Shared Add-ins中加载自定义函数我们可以在OnConnection方法中,调用如下方法:
MSExcel.AddIn excelFunc = null;
try
{
excelFunc = applicationObject.AddIns.Add(“your .xla file path“, true);
}
catch (System.IO.IOException exception)
{
LogHelper.Error("IOException:未发现xla文件在所设置路径", exception);
}
catch (Exception exception)
{
LogHelper.Error(exception);
}
在大多数情况下,如果用户直接打开Excel应用程序,插件加载就会执行OnConnect方法,就会执行加载.xla函数的逻辑。
但是,更多的情况是,用户会直接双击一个之前保存过的,包含有我们的.xla文件中的自定义函数的excel文件,通过这种方式打开excel,插件的加载.xla在某些情况下回出现加载不了的情况。出现该问题的原因在于,我们再加载.xla文件的时候,必须要确保当前Excel中有一个空白的Sheet页处于打开状态。在用户通过双击现有的excel文件的时候,在文档打开之前,并没有可用的Sheet页处于打开状态,这是我们的插件加载.xla文件的时候就会出现加载不上的问题。
解决方法就是在OnConnect中调用RegisterOpenEvent方法注册WorkbookActivate事件,在该事件回调方法中去注册.xla文件。这样在文件被打开的时候就可以加载.xla或者.xll函数了,在加载完函数之后,我们需要注销该事件以防止重复加载。如下
private void RegisterOpenEvent()
{
applicationObject.WorkbookActivate += new MSExcel.AppEvents_WorkbookActivateEventHandler(applicationObject_WorkbookActivate);
} /// <summary>
/// This active evevt was designed to be trigged only once to load xla file
/// </summary>
/// <param name="Wb"></param>
void applicationObject_WorkbookActivate(MSExcel.Workbook Wb)
{
MSExcel.AddIn excelFunc = null;
try
{
excelFunc = applicationObject.AddIns.Add(RuntimeHelper.MapRootPath(EmOfficeCore.Helper.PathHelper.Instance.EMFuncPath), true);
}
catch (System.IO.IOException exception)
{
LogHelper.Error("IOException:未发现xla文件在所设置路径", exception);
}
catch (Exception exception)
{
LogHelper.Error(exception);
}
if (excelFunc.Installed == true)
{
applicationObject.WorkbookActivate -= new MSExcel.AppEvents_WorkbookActivateEventHandler(applicationObject_WorkbookActivate);
}
else
{
applicationObject.WorkbookActivate -= new MSExcel.AppEvents_WorkbookActivateEventHandler(applicationObject_WorkbookActivate);
excelFunc.Installed = true;
}
}
这样就能解决加载不上的问题。
五 资源释放不掉的问题
在使用Shared Add-ins开发插件的时候,通常如果资源释放处理不好,会存在关闭Excel后,任务管理器中的Excel.exe这个进程没有关闭。这是由于我们在.NET中引用了非托管代码 ,但是有没有手动释放,导致资源没有被回收导致的。该问题在StackOverflow上有很详细的讨论,按照msdn上的解决方法。我们只需要在OnDisConnection 方法中对资源进行释放即可:
/// <summary>
/// Implements the OnDisconnection method of the IDTExtensibility2 interface.
/// Receives notification that the Add-in is being unloaded.
/// </summary>
/// <param term='disconnectMode'>
/// Describes how the Add-in is being unloaded.
/// </param>
/// <param term='custom'>
/// Array of parameters that are host application specific.
/// </param>
/// <seealso class='IDTExtensibility2' />
public void OnDisconnection(Extensibility.ext_DisconnectMode disconnectMode, ref System.Array custom)
{
try
{
GC.Collect();
Marshal.FinalReleaseComObject(applicationObject);
GC.Collect();
}
catch (Exception ex)
{
LogHelper.Error(ex);
}
}
六 正确的创建和使用Excel实例
在应用程序开发中,通常我们需要在Winform中导出到Excel或者对Excel文件进行读写,如果您选择使用Excel API的话(当然更好的方式是直接使用OpenXML或者相似的技术直接生成Excel文件),通常的做法是直接创建一个Excel实例:
Microsoft.Office.Interop.Excel.Application m_objExcel = new Microsoft.Office.Interop.Excel.Application();
但是这种方式过于简单粗暴, 他相当于直接在后台创建一个Excel的实例。当您导出多次的时候会创建多个这样的应用程序,并且在关闭程序的时候很可能导致这些资源不能释放,最明显的是您会发现在资源管理器中会出现很多个Excel的进程没有被关闭。
还有一个场景就是插件的自动升级。 通常我们的插件需要升级,如果发现新的版本,则回去下载,然后对现有的dll进行覆盖。通常,改升级程序时一个独立于excel的插件,覆盖之前通常需要关闭当前打开的Excel才能进行覆盖。在检测到升级并下载完新的升级包时,需要提示用户关闭Excel,点击确定的时候,一般的做法是强制终止任务管理器中的Excel进行,再执行覆盖,这样做的问题在于:Excel会认为插件导致了Excel的意外关闭,在下次打开的时候,会直接提示改插件存在严重问题,是否禁用。通常一般的用户会去点击禁用。这样显然不好。
打开或者获取Office产品实例的方法有很9种,比较友好的方式是,如果当前已经有Excel的实例在运行,则不要去new新的实例,而是通过一些方法直接从现有的实例中去获取和创建,比如可以通过Marshal.GetActiveObject方法传入想要获取实例的ProgID即可。对于上面的方法,更友好的版本是:
public Microsoft.Office.Interop.Excel.Application StartExcel()
{
Microsoft.Office.Interop.Excel.Application instance = null; try
{
instance = (Microsoft.Office.Interop.Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
}
catch (System.Runtime.InteropServices.COMException ex)
{
instance = new Microsoft.Office.Interop.Excel.Application();
} return instance;
}
该方法首先尝试使用GetActiveObject从当前活动的Excel实例获取实例,如果没有活动的Excel,则再新建一个Excel实例。这样就避免了肯能的资源浪费。
在升级程序中,我们可以直接调用该方法返回的实例,然后调用它的Quit方法就可以。
七 Excel 2003上安装部署不上的问题
使用Shared Com Add-in创建的程序在Office 2003上有可能安装不上, 该问题在前一篇有关Excel安装部署中 提到过,需要安装两个针对Office 2003的补丁。这篇文章Deploying a Shared COM add-in for Office 2003 (Visual Studio 2008 SP1) [and how to work around a known issue which causes the add-in to fail to load if KB908002 is not installed.] 有详细介绍该补丁如何在部署时打包及安装,这里就不在赘述了。
出处:http://www.cnblogs.com/yangecnu/
本作品由yangecnu 创作,采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。 欢迎转载,但任何转载必须保留完整文章,在显要地方显示署名以及原文链接。如您有任何疑问或者授权方面的协商,请 给我留言。
Excel开发的更多相关文章
- 浅谈Excel开发:十一 针对64位Excel的插件的开发和部署
自Office 2010版本开始有了32位和64位之分,对Excel来说,32位的Excel和64位的Excel在性能上的主要区别是64位的Excel能够处理2G及2G以上的大数据集. 随着64位操作 ...
- 浅谈Excel开发:八 Excel 项目的安装部署
前面几篇文章讲解了Excel开发的几个比较主要的也是比较重要的方面,比如菜单系统,Excel对象模型,自定义函数,RTD函数,异步自定义函数,用户自定义任务面板等,在实际开发中我们还会遇到各种“千奇百 ...
- 浅谈Excel开发:七 Excel 自定义任务窗体
前面花了三篇文章讲解了Excel中的UDF函数,RTD函数和异步UDF函数,这些都是Excel开发中的重中之重.本文现在开始接着第二篇文章的菜单系统开始讲解Excel中可供开发的界面元素,本文要讲解的 ...
- 浅谈Excel开发:三 Excel 对象模型
前一篇文章介绍了Excel中的菜单系统,在创建完菜单和工具栏之后,就要着手进行功能的开发了.不论您采用何种方式来开发Excel应用程序,了解Excel对象模型尤其重要,这些对象是您与Excel进行交互 ...
- 浅谈Excel开发:二 Excel 菜单系统
在开始Excel开发之前,需要把架子搭起来.最直接的那就是Excel里面的菜单了,他向用户直观的展现了我们的插件具有哪些功能.菜单出来之后我们就可以实现里面的事件和功能了.Excel菜单有两种形式,一 ...
- 浅谈Excel开发:一 Excel 开发概述
做Office相关的开发工作快一年多了,在这一年多里,在插件的开发中遇到了各种各样的问题和困难,还好同事们都很厉害,在和他们的交流讨论中学到了很多的知识.目前Office相关的开发资料是比较少 ...
- Excel 开发概述
浅谈Excel开发:一 Excel 开发概述 做Office相关的开发工作快一年多了,在这一年多里,在插件的开发中遇到了各种各样的问题和困难,还好同事们都很厉害,在和他们的交流讨论中学到了很多的知识. ...
- 【转载】浅谈Excel开发:一 Excel 开发概述
博客园就是好,想要什么都给总结了,多谢 原文转载:http://www.cnblogs.com/yangecnu/p/Excel-Develpment-Introduction.html 做Offic ...
- 浅谈Excel开发:二 Excel 菜单系统(转)
编辑器加载中...http://www.cnblogs.com/yangecnu/p/Excel-Menu-System-Introduction.html 在开始Excel开发之前,需要把架子搭起来 ...
随机推荐
- java:高速排序算法与冒泡排序算法
Java:高速排序算法与冒泡算法 首先看下,冒泡排序算法与高速排序算法的效率: 例如以下的是main方法: /** * * @Description: * @author:cuiyaon ...
- Android_显示器本身被卸载应用程序
1.经jni实现功能 //LOG宏定义 #define LOG_INFO(tag, msg) __android_log_write(ANDROID_LOG_INFO, tag, msg) #defi ...
- Angularjs -- 核心概念
angularjs旨在减轻使用AJAX开发应用程序的复杂度,使得程序的创建.測试.扩展和维护变得easy.以下是angularjs中的一些核心概念. 1. client模板 多页面的应用通 ...
- Java多线程的~~~Lock接口和ReentrantLock使用
在多线程开发.除了synchronized这个keyword外,我们还通过Lock接口来实现这样的效果.由Lock接口来实现 这样的多线程加锁效果的优点是非常的灵活,我们不在须要对整个函数加锁,并且能 ...
- MSSQL Server 2008 数据库安装失败
1.Reporting Services目录临时数据库文件存在 出现这种问题的原因,是由于以前安装的SQL Server2008文件并没有卸载或删除干净造成 解决的办法如下: 找到 ...
- 脉冲神经网络Spiking neural network
(原文地址:维基百科) 简单介绍: 脉冲神经网络Spiking neuralnetworks (SNNs)是第三代神经网络模型,其模拟神经元更加接近实际,除此之外,把时间信息的影响也考虑当中.思路是这 ...
- VS2012 update1 和 VS2012 Lang Pack 离线安装方法
原文:VS2012 update1 和 VS2012 Lang Pack 离线安装方法 最近有需要用VS2012打开ReactOS这个大项目,生成sln后打开用来导航代码什么的,但其代码都是ascii ...
- APP-随身听
简单到复杂听你的专属音响界,听金融.听物业,听新闻和其他节目专辑,简要介绍了新的音频应用,给你不一样的聆听体验.还记得老歌做?这里有.您留声机的一部分!很简单的音频应用,随时随地与此应用程序来听你的私 ...
- C++中怎样获取类成员的指针
我们都知道C++ class中有三种成员函数,static(静态的),nonstatic(非静态的),virtual(虚拟的)各种成员函数的指针各有差别,下面是一个完整的样例:(注意红颜色的差别 ...
- 【MS SQL】通过执行计划来分析SQL性能
原文:[MS SQL]通过执行计划来分析SQL性能 如何知道一句SQL语句的执行效率呢,只知道下面3种: 1.通过SQL语句执行时磁盘的活动量(IO)信息来分析:SET STATISTICS IO O ...