C#开发Excel扩展插件

如何用C#开发Excel扩展插件

文章源处:https://www.cnblogs.com/bobird/articles/2871265.html(权侵删)

文章出处    http://support.microsoft.com/?kbid=302901

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

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

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

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

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

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

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

 

 

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

 

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

Ø         (.NET)Extensibility

Ø         (COM)Microsoft 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, objectAddInInst, 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 MyFunctions :  ExcelUDFBase

    {

        ///

 

        /// 这是个简单的样例函数。它的逻辑非常简单,无需过多解释。需要指出的是这个函数的返回值是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接口的主要目的是为了获得指向Excel和AddIn的两个变量。有了这两个变量,我们就可以做一些比较高级开发工作。其中最简单但是最重要的大概是编写所谓的易变函数(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平台提供的强大功能根据需要来开发更为复杂的用户自定义函数。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: WinForms是Microsoft .NET Framework中的一种应用程序开发框架,它提供了一种创建Windows应用程序用户界面的简单方法。 WinForms使用基于事件的模型来处理用户交互,并且使用面向对象的方法来构建应用程序。它提供了许多预定义的控件,如按钮、文本框、列表框等,开发者可以通过在设计视图中拖拽和放置这些控件来创建用户界面。同时,开发者也可以通过编写代码来控制控件的行为和属性。 WinForms具有很强的可定制性,开发者可以通过设置控件的属性来改变其外观和行为,还可以通过继承现有的控件来创建自定义控件。除了提供基本的Windows控件,WinForms还支持绘制自定义的图形和控件,以满足特定的应用需求。 WinForms提供了一套简单易用的事件处理机制,开发者可以为控件注册事件处理方法,当事件发生时,这些方法会被自动调用。开发者还可以添加各种事件处理器来响应用户的操作,如按钮的点击事件、鼠标移动事件等。 WinForms还提供了数据绑定功能,使开发者能够将控件与数据源相绑定,实时反映数据的变化。这样,开发者就可以简单地操作数据,并将其显示在界面上,而无需手动处理数据的更新和刷新。 总而言之,WinForms是一个功能强大且易于使用的框架,它使开发者能够快速创建Windows应用程序,并提供了丰富的功能和可定制性。无论是初学者还是经验丰富的开发者,都可以轻松上手并发挥其优势。 ### 回答2: WinForm C# 是一种开发桌面应用程序的技术,它是使用C#语言在Windows操作系统上开发的。使用WinForm C#可以快速、简单地创建具有丰富用户界面和功能的应用程序。 WinForm C#提供了一系列的控件和功能,可以方便地进行用户界面的设计和开发。通过拖拽控件,设定属性,以及编写事件处理方法,我们可以轻松地实现按钮、文本框、列表框、菜单等常见的界面元素。同时,WinForm C#还提供了丰富的布局方式,可以让用户界面更加美观、易于操作。 除了用户界面,WinForm C#还提供了很多有用的功能。例如,我们可以利用WinForm C#来访问数据库,进行数据的增删改查操作。我们也可以使用WinForm C#来操作文件系统,创建、读取、写入文件等。此外,WinForm C#还支持网络编程,可以实现与远程服务器的通信。 使用WinForm C#开发应用程序具有很多优点。首先,它基于.NET框架,拥有强大的功能和性能。其次,WinForm C#具有良好的可视化开发环境,使开发人员可以更快速地进行开发和调试。此外,WinForm C#还提供了丰富的文档和示例代码,方便开发人员学习和使用。 总之,WinForm C#是一种强大的开发技术,可以帮助我们快速开发出功能强大、界面友好的桌面应用程序。无论是初学者还是经验丰富的开发人员都可以借助WinForm C#开发自己的应用程序。 ### 回答3: WinForms是一种用于创建Windows桌面应用程序的用户界面框架,它是基于.NET平台的一部分。通过使用C#编程语言,开发人员可以使用WinForms快速构建交互式和功能丰富的Windows应用程序。 WinForms提供了一组丰富的控件,如文本框、按钮、标签等,这些控件可以自由布局在窗体上,以构建用户友好的界面。此外,WinForms还支持数据绑定和事件处理,使开发人员能够轻松地控制用户界面和处理用户操作。 WinForms还具有良好的可定制性和扩展性。开发人员可以根据自己的需要自定义控件的外观和行为,以满足特定的应用程序需求。此外,通过使用第三方控件库,开发人员可以进一步扩展WinForms的功能。 在使用WinForms进行C#开发时,开发人员首先需要创建一个窗体类,窗体类是应用程序的主要界面。然后,通过在窗体类中添加控件并编写事件处理程序,可以实现用户界面和交互逻辑。 WinForms使用面向对象的编程模式,开发人员可以通过继承窗体类和控件类来创建自定义控件,并重写各种方法以实现特定的行为。 总之,WinForms是一个功能强大且易于使用的框架,它与C#编程语言紧密结合,可以帮助开发人员快速构建Windows桌面应用程序。无论是个人开发者还是企业开发人员,都可以通过学习和使用WinForms来实现他们的应用程序开发需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值