Excel自定义函数
- 格式:pdf
- 大小:212.39 KB
- 文档页数:6
Excel⾃定义函数
我们知道,Excel中有很多内置的函数,⽐如求和,求平均,字符串操作函数,⾦融函数等等。在有些时候,结合业务要求,这些函数可
能不能满⾜我们的需求,⽐如我想要⼀个函数能够从WebService上获取某只股票的最新价;我想要⼀个函数能够获取当前的天⽓情况,这
些需求我们可以通过编写Excel⾃定义函数(User Define Function ,UDF )来实现,这样,在Excel中直接调⽤我们的⾃定义函数即可满⾜特定
的业务需求,⼀般地,因为这种⾃定义函数的粒度相对较⼩,所以我们可以根据业务需求编写很多基础的⾃定义函数,然后以这些⾃定义函
数为基础,编写各种复杂的分析报表。
编写UDF的⽅式有很多种,⽐如直接在VBA种编写⾃定义函数;如果您熟悉C++,可以将⾃定义函数编写到XLL中,不熟悉也可以使⽤
ExcelDNA这个开源的库使⽤.NET技术也可以将您的代码编译为XLL;如果熟悉.NET,使⽤C#编写⾃定义函数类库,然后将类库注册成
Com组件也可在Excel中调⽤。下⾯就这⼏种⽅式简要介绍,并给出其优缺点。
1. 使⽤C# 类库注册的⽅式实现Excel⾃定义函数
我⾃⼰对.NET 较熟悉,所以⾸先介绍这种在.NET中即可进⾏Excel⾃定义函数开发的模式,这种⽅法相对简单。在开始之前,还是回到
我们对YY插件的规划,我们的YY插件有天⽓,财经,地图等功能,现在我们假设需要⼀个天⽓⾃定义函数,通过该函数能够获取某个城市
某⼀天的天⽓情况,⽐如说⽓温。
⾸先我们需要创建⼀个简单的C#类库,如下图,其名为YYWeatherUDF。
然后,我们创建⼀个所有⾃定义函数的基类UDFBase.cs,在该类中,我们放⼀些基本的注册Com组件所需要的⼀些操作以及屏蔽⼀些
Object的对象的⽅法使其不要出现在Excel的UDF函数中来。有⼀点需要注意的是,在注册及取消注册为Com组件的时候,为避免Excel找不
到mscoree.dll,需要往注册表中写⼊其全部路径,下⾯的代码即为实现这⼀功能。
public abstract class UDFBase
{
///
/// 解决在某些机器的Excel提⽰找不到mscoree.dll的问题
/// 这⾥在注册表中将该dll的路径注册进去,当使⽤regasm注册该类库为com组件
/// 时会调⽤该⽅法
///
///
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
{
Registry.ClassesRoot.CreateSubKey(
GetSubKeyName(type, "Programmable"));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(
GetSubKeyName(type, "InprocServer32"), true);
key.SetValue("", System.Environment.SystemDirectory + @"\mscoree.dll",
RegistryValueKind.String);
}
[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type)
{
Registry.ClassesRoot.DeleteSubKey(
GetSubKeyName(type, "Programmable"), false);
}
private static string GetSubKeyName(Type type, string subKeyName)
{
return string.Format("CLSID\\{{{0}}}\\{1}", type.GUID.ToString().ToUpper(), subKeyName);
}
}
///
/// 将Object类的四个公共⽅法隐藏
/// 否则将会出现在Excel的UDF函数中
///
///
[ComVisible(false)]
public override string ToString()
{
return base.ToString();
}
[ComVisible(false)]
public override bool Equals(object obj)
{
return base.Equals(obj);
}[ComVisible(false)]
public override int GetHashCode()
{
return base.GetHashCode();
}
以上这些代码是⼀个在C# 创建⼀个UDF类的基本代码,我们可以将该代码保存为基类。
现在我们要编写我们⾃⼰的实际的UDF函数了,新建⼀个名为WeatherFunc的类,继承⾃上⾯的UDFBase抽象类,并在类的属性上添加
⼀些⾃定义属性,这些属性在后⾯注册为Com组件的时候需要⽤到。ClassInterface类的构造函数中参数ClassInterfaceType.AutoDual表⽰
两边都传递,这就回是的Object类的所有公共⽅法都会显⽰出来,如果采⽤实现接⼝的⽅式,将该熟悉设置为None即可解决多余⽅法出现
在UDF列表中的问题,这⾥不细讲,继续。
[Guid("5268ABE2-9B09-439d-BE97-2EA60E103EF6")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class WeatherFunc : UDFBase
{
public WeatherFunc()
{ }
}
其中Guid可以使⽤Visual Studio⾃带的⼯具⽣成,如果我们不指定,则Visual Studio在将该类注册为Com组件时,调⽤regasm⼯具的时
候会⾃动⽣成⼀个Guid,在开发过程中,⼀般我们会⼿动指定⼀个Guid,这样在调试的时候我们可以根据Guid在注册表中去查找该项,看
是否正常注册为了Com组件。
///
/// 根据城市和⽇期,返回当天的天⽓描述
///
/// 城市
/// ⽇期
///
public String YY_Weather_Condition(String city, DateTime day)
{
Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
return weather.Condition.Text;
}
///
/// 根据城市和⽇期,返回当天的⽓温状况
///
/// 城市
/// ⽇期
///
public double YY_Weather_Temperature(String city, DateTime day)
{
Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
return weather.Condition.Temperature;
}
///
/// 根据城市和⽇期,返回当天的风速
///
/// 城市
/// 城市
///
public double YY_Weather_WindSpeed(String city, DateTime day)
{
Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
return weather.Wind.Speed;
}
这样我们的三个UDF函数已经写好了,然后右击⼯程项⽬,在属性设置-〉⽣成 注册为Com组件。
这⾥注册为Com组件时,Visual Studio其实是去调⽤regasm 将类库注册为Com组件,并在注册表⾥⾯写⼊⼀些信息。在发布到客户端上
部署的时候,我们可以直接导⼊该类库的相关注册表信息,或者直接调⽤regasm在客户的机器上写⼊这些信息,在后⾯讲到Excel插件安装
部署的时候,会说到这些。
然后我们直接进⾏编译。因为注册Com组件涉及对注册表进⾏操作,在XP以上系统中,需要管理员权限,如果当前Visual Studio不是以
管理员⾝份运⾏。则会出现下⾯错误:
保存退出,然后右键选择以管理员权限打开VS,然后重新编译。
完成之后,我们根据之前的GUID 5268ABE2-9B09-439d-BE97-2EA60E103EF6 到注册表中去查找,可以看到,编译并注册为Com组件
后会到注册表中写⼊⼀些信息,这些情况在安装Office等软件的时候,最后⼀步的时候,⼀般可以看到正在注册组件,然后后⾯是不停闪动
GUID,应该是在做相同的⼯作。我机器上截图如下。
现在我们打开Excel软件,在开发⼯具-〉加载项中,将我们的⾃定义函数加载进来。
现在,在公式->插⼊函数中可以看到我们编写的⾃定义函数。