打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
如何用C#开发Excel扩展插件
毫无疑问,微软公司的Excel是一个非常成功的应用软件。它不仅本身功能强,而且还允许用户根据自己需要进行再开发以扩展其功能。传统上,我们可以用C/C++语言或者VBAExcel进行扩展性开发。C/C++功能强大,但是开发工作比较复杂;VBA使用起来非常方便,但是功能有限。.NET的推出为我们提供了一种能够结合这两者长处的再开发手段。基于.NET的解决方案可以利用所有.NET开发平台提供的强大功能,例如多线程编程、分布式计算等。这都是VBA难以做到的,事实上即使使用C/C++,我们也很难实现这些功能。不仅如此,我们还可以充分利用Visual Studio的整体开发环境,例如版本控制之类的功能。这些功能对于团队开发非常重要,但是在VBA开发环境下则非常困难。

本文将以C#为例介绍对Excel进行再开发的方法和技巧。我们通常有三种方法来对Excel进行再开发:

一是扩展插件(AddIn)。这是开发Excel用户自定义函数的首选。

二是VSTOVisual Studio Tool for Office)。这是开发Excel内嵌功能的首选(例如按钮、菜单等等)。

三是RTDReal Time Data)。这是开发Excel实时数据应用程序的首选。

尽管它们针对的用途不同,但是开发的基本手段和过程是非常类似的。在技术细节上,这三种方法主要的不同是需要实施不同的接口。在本文中,我们将主要介绍利用C#开发Excel扩展插件的方法。读者可以依次类推在需要的时候开发其它两类的程序。

首先,创建一个C#库程序(library)并指定这个类程序库“控件可见”(Com Visible)。这通常是通过项目属性、Assembly属性来指定的,如下图所示。(注意不同版本的Visual Studio可能对话框的样子不同)。

 

为了方便起见,我们还可以让程序自动注册成控件。这可以通过项目属性、编译属性来指定,如下图所示。如果我们不指定这个属性的话,或者我们需要在其它计算机上使用这个程序的话,我们可以使用.NET平台自带的RegAsm.exe来手工进行注册。

其次,我们的项目需要添加以下两个引用:

         .NETExtensibility

         COMMicrosoft Office Excel Object Library(选用最新版本)

然后,输入以下程序。程序中的注释已经对各部分的作用作了适当说明。注意,这个类程序并不是Excel用户自定义函数本身,而是包含了所有需要的基本架构函数。有了这个基类以后,我们就可以编写一个简单的子类仅仅包含我们需要的Excel用户自定义函数。

 

 

using System;

using System.Runtime.InteropServices;

using Extensibility;

using MyWin32 = Microsoft.Win32;

using MsExcel = Microsoft.Office.Interop.Excel;

 

namespace MyExcelAddIn

{

    /// Excel用户自定义函数的基类,包含了所有必需的基础架构类函数。它的子类则可以专注于用户自定义函数的编写。

    public class ExcelUDFBase : IDTExtensibility2

    {

        /// 这个函数将在我们的AddIn被注册时调用。

        [ComRegisterFunctionAttribute]

        public static void RegisterFunction(Type type_)

        {

            MyWin32.Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type_, "Programmable"));

 

            // 以下这两个函数调用不是必须的。但是省略它们的话,每次我们从EXCEL中引用或取掉这个AddIn时,EXCEL都会提示找不到mscoree.dll,问你

            // 是否要删掉这个AddIn。当然我们应该回答“不”。

            MyWin32.RegistryKey key = MyWin32.Registry.ClassesRoot.OpenSubKey(GetSubKeyName(type_, "InprocServer32"), true);

 

            key.SetValue(""

, String.Format("{0}\\mscoree.dll", System.Environment.SystemDirectory)

, MyWin32.RegistryValueKind.String

);

        }

 

        /// 这个函数将在我们的AddIn被注销时调用。

        [ComUnregisterFunctionAttribute]

        public static void UnregisterFunction(Type type_)

        {

            MyWin32.Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type_, "Programmable"));

        }

 

        /// 工具函数。

        private static string GetSubKeyName(Type type_, String sub_key_ame_)

        {

            return String.Format("CLSID\\{{{0}}}\\{1}", type_.GUID.ToString().ToUpper(), sub_key_ame_);

        } 

 

        #region IDTExtensibility2 Members

        /// 这个变量将指向Excel应用程序。

        protected MsExcel.Application MyExcelAppInstance { get; private set; }

 

        /// 这个变量将指向我们的AddIn

        protected object MyAddInInstance { get; private set; }

 

        /// 这个函数和以下四个函数都是为了实施IDTExtensibility2接口。实施IDTExtensibility2接口并不是必须的。但是如果我们不实施这个接口的

 /// 话,我们将无法得到从而无法编写Volatile函数。

        public void OnAddInsUpdate(ref Array custom)

        {

        }

 

        public void OnBeginShutdown(ref Array custom)

        {

        }

 

        public void OnConnection(object Application, ext_ConnectMode ConnectMode, object AddInInst, ref Array custom)

        {

            MyExcelAppInstance = (MsExcel.Application)Application;

 

            MyAddInInstance = AddInInst;

        }

 

        public void OnDisconnection(ext_DisconnectMode RemoveMode, ref Array custom)

        {

        }

 

        public void OnStartupComplete(ref Array custom)

        {

        }

        #endregion

    }

}

 

最后我们可以输入以下程序来创建了我们第一个用户自定义函数。(当然,另写一个类不是必须的,我们也可以把这个函数直接写在ExcelUDFBase类里。)

 

using System;

using System.Runtime.InteropServices;

using MsExcel = Microsoft.Office.Interop.Excel;

 

namespace MyExcelAddIn

{

 /// 这个类包括我们真正需要的用户自定义函数。它的两个类属性是必须的。但是每个这样的类应该具有唯一的GUID值。GUID可以用Visual Studio自己生成。

 /// 我们只要选择菜单中的工具(Tools),然后选择GUID选项就可以了。   

 [ClassInterface(ClassInterfaceType.AutoDual), ComVisible(true)]

   [Guid("348E9F3A-96E4-42da-A5B9-FAD52E7744BB")]

    public class MyFunctionsExcelUDFBase

    {

        /// 这是个简单的样例函数。它的逻辑非常简单,无需过多解释。需要指出的是这个函数的返回值是object以及其内部的try . . . catch程序结构。

        /// 当程序出错的时候,这样的结构可以使我们的用户自定义函数返回合适的错误信息。

        public object MyDivid(double Value1, double Value2)

        {

            try

            {

                return Value1 / Value2;

            }

            catch (Exception err_)

            {

                return err_.ToString();

            }

        }

 }

}

 

编译好之后,我们就可以启动Excel。先从菜单上选择“工具”(Tools)、“插件”(AddIn),然后点击“自动插件”(Automation)按钮。然后在跳出的对话框中选择MyExcelAddIn.MyFunctions。如果一切顺利的话,我们就可以使用我们刚才编写的MyDivid()函数了,如下图所示:

 

一个常见的可能问题是Excel.NET版本不兼容。例如如果你使用的是Office 2002版而程序是用Visual Studio 2005版开发的。这时候,你就需要告诉Excel加载合适的.NET运行环境。这其实很简单,只要创建一个内容如下的文本文件,命名为excel.exe.config,并把它保存在excel.exe同一个目录下就可以了。

 

xml version=”1.0”?>
<configuration>
  <startup>
    <supportedRuntime version=”v2.0.50727”/>
  startup>
configuration>

 

至此,我们可以看到用C#开发Excel控件基本上和开发其它应用程序一样简单。我们唯一需要添加的就是在文章一开头ExcelUDFBase类里定义的几个函数,而这几个函数完全可以照抄。事实上,如果我们只要编写类似于MyDivid()这样的函数的话,我们甚至无需实施IDTExtensibility2接口,即只需要RegisterFunction()UnregisterFunction()这两个函数就可以了。实施IDTExtensibility2接口的主要目的是为了获得指向ExcelAddIn的两个变量。有了这两个变量,我们就可以做一些比较高级开发工作。其中最简单但是最重要的大概是编写所谓的易变函数(Volatile)。熟悉Excel用户自定义函数的读者应该知道非易变函数只要输入没有变化,Excel就不会重新调用该函数。而易变函数则没有这个限制。用C#编写易变函数其实很容易,只要在相应的函数里首先调用MyExcelAppInstance.Volatile(Type.Missing)就可以了,如下所示:

  

        /// 这个函数是一个易变(Volatile)函数的例子。我们只要在相应函数的开头加上MyExcelAppInstance.Volatile(Type.Missing)就可以

        public double MyRand()

        {

            MyExcelAppInstance.Volatile(Type.Missing);

 

            return m_random.NextDouble();

        }

  

        private Random m_random = new Random();

C/C++开发过Excel用户自定义函数的读者一定知道内存管理是个大问题,甚至传递一个字符串也需要考虑怎么释放内存。但是用C#则没有这个问题,甚至C#会为我们自动进行类型转换。请见下面这个例子:

 

        public object ShowInfo(String Name, DateTime When, MsExcel.Range Dummy)

        {

            try

            {

                return String.Format("{0} selected {2} cells at {1}.", Name, When, Dummy.Cells.Count);

            }

            catch (Exception err_)

            {

                return err_.ToString();

            }

        }

}

 

一个例子如下图所示:

 

另外一个常用技巧是函数参数的缺省值。我们知道C#一般不支持缺省参数,但是在这里我们却可以使用缺省参数。

   /// 使用缺省参数只要使用Optional这个属性就可以了。

  public object MyEcho([Optional, DefaultParameterValue("Buddy")]String Name)

  {

      try

      {

          return Name;

      }

      catch (Exception err_)

      {

          return err_.ToString();

      }

}

 

一个例子如下图所示:

至此,我们已经介绍了利用C#开发Excel控件的基本方法和一些基本技巧。由此出发,我们就可以利用.NET平台提供的强大功能根据需要来开发更为复杂的用户自定义函数。


AddToolBar()方法

private void AddToolBar()
   {
       Office.CommandBars bars =
AppExcel.CommandBars;
            
       if (bars == null
)
           return
;

       foreach (Office.CommandBar bar in
bars)
       {
           if (bar.Name.ToLower().Trim() == "mzbar"
)
           {
               bar.Delete();
           }
       }

       Office.CommandBar mzBar = AppExcel.CommandBars.Add("mzBar", 1, null, null
);
       if (mzBar != null
)
       {
           btnCalc = (Office.CommandBarButton)mzBar.Controls.Add(Office.MsoControlType.msoControlButton, missing, missing, 1, true
);
           if (btnCalc != null
)
           {
               btnCalc.Caption = "计算(&C)"
;
               btnCalc.Style =
Office.MsoButtonStyle.msoButtonIconAndCaption;
               btnCalc.TooltipText = "计算"
;
               btnCalc.FaceId = 3277
;
               btnCalc.Click += new
Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler(btnCalc_Click);
           }
           mzBar.Visible = true
;
       }
   }

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
[小结]VSTO addin 安装部署
浅谈Excel开发:一 Excel 开发概述
寻找Excel2007中消失的简繁转换功能--太平洋电脑网Pconline-[Excel]
【C#】23. Excel Addin 开发(1)
你还在为函数的一对多查找问题而烦恼吗?自定义函数轻松解决它
OFFICE 的加载项(add in)(转)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服