前段时间装了个visual studio 2010,试着用里面的VSTO4.0,但是对如何生成一个自定义函数始终搞不明白(之前也看了《VSTO开发指南》,但觉得里面所讲的东西太泛了,而且版本不一样,形式也改变了不少),终于在网上看到有人写出一个完整的过程(原文请看/brooks-dotnet/archive/2011/01/16/1936871.html),但在实操中还是有不少问题,但经过多次尝试,终于解决了所遇到的问题,现在我就根据原文的内容以及建立过程中所遇到的问题,重新整理后讲述建立一个自定义函数的过程。
一、启动VS2010,(这里尝试着用C#来编写)新建一个类库,填好名称之后按确定,开始编码。
二、进入编程界面后,先引用必须的类库
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using Microsoft.Office.Interop.Excel
设置GUID及COM的一些特性
[Guid("A4AAE79B-9587-4014-BABB-966C5DF76C83")]
[ClassInterface(ClassInterfaceType.AutoDual),ComVisible(true)]
如图示:
Guid这个标识码可用LINQPad程序来获取(可从/下载)
在类中,除了有函数主体外,还必须有注册及注销时的行为语句,所以必须添加以下语句:#regi on COM Related
[ComRegisterFunction]
public static void Regi sterFunction(Type type)
{
Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type, "Programmable"));
var key = Registry.ClassesRoot.OpenSubKey(GetSubKeyName(type, "InprocServer32"), true);
key.SetValue("", Environment.SystemDirectory + @"\mscoree.dll", Regi stryValueKind.String);
}
[ComUnregisterFunction]
public static void Unregi sterFuncti on(Type type)
{
Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type, "Programmable"), false);
}
private static string GetSubKeyName(Type type, string subKeyName)
{
var s = new System.Text.StringBuilder();
s.Append(@"CLSID\{");
s.Append(type.GUID.ToString().ToUpper());
s.Append(@"}\");
s.Append(subKeyName);
return s.ToString();
}
#endregi on
如图示:
三、这些准备工作完毕后就可以写自己的函数主体了,这里以一个自定义的字符串联结为例:
public string MyConcate(params Object[] values)
{
string iStr = "";
Range iRng;
for (int iStep = 0; iStep < values.Length; iStep++)
{
if (values[iStep].ToString() == "System.__ComObject")
{
iRng = (Range)val ues[iStep];
if (iRng.Count > 1)
{
foreach(Range cRng in iRng)
{
iStr += Convert.ToString(cRng.Value);
}
}
else
{
iStr += Convert.ToString(iRng.Value);
}
}
else
{
iStr += values[iStep].ToString();
}
}
return iStr;
}
注:由于这里是用了params来传递不定数量的参数,所以需要把Object强制转换为Range类型,否则直接写iStr += values[iStep].ToString(); 只能获取到一个“Object”字符串,由于需要强制转换,所以要加入另外一个引用using Microsoft.Office.Interop.Excel;(此引用需事先在解决方案资源管理器那里添加,否则无法引用)
四、编写函数完毕,即可进行编译生成,在编译之前,有必要设置一些选项。
进入菜单栏-》项目-》(项目名称)属性
打开属性设置窗体,进入“生成”项
其中的“为COM互操作注册”,如果你的系统是WIN7,那就不要选择此项,你选择了的话,由于权限问题,在编译的时候就会出现错误,导致无法编译成功,但即使是在XP的情况下,编译成功了,但在加载的时候仍不能自动注册,导致加载不成功,不知道是不是VSTO4.0的缘故,所以这项如果选了的话就把它取消。
如果你想调试程序,那么就可以进入“调试”项,选择“启动外部程序”然后选择EXCEL程序作为函数调试的实体
设置好后就可以生成项目了。
五、注册加载DLL
注册与注销DLL需要一个regasm程序来完成,如果你装的是.NetFrameWork4.0,那么这个程序就在%windir%\\Framework\v4.0.30319文件夹下,我们打开CMD,进入此文件夹,如图示:
这里要注意的一点是,如果你的系统是Win7或Vista,那么你运行CMD时必须是以管理员的身份运行,否则的话会因为权限问题,在注册时无法向注册表写入数据导致注册不成功。
进入文件夹后,输入注册语句为DLL进行注册,如图示:
Regasm有多个运行参数,详细可通过帮助查看/help
回车运行后,显示如下信息:
因为是未签名程序集,所以会有警告,你在项目属性那里设置好签名就不会有这样的警告了。
现在这个DLL已经注册成功,可以在EXCEL中引用这个DLL并使用其中所写的自定义函数了。
以EXCEL2003为例来使用刚注册的这个DLL(2007、2010只是在引用的操作上有所不同),打开EXCEL,(菜单栏)工具-》加载宏-》自动化
在弹出的窗口中找到并选择刚才自己写的那个类文件,按两次确定后,即加载成功
加载完毕就可以在工作页面中使用所编写的自定义函数了。
至此,一个由C#编写的自定义函数就可以正常使用了。
六、注销DLL
当这个自定义的DLL不再需要时,该如何注销呢,其过程跟注册差不多,只是在应用regasm时的参数有所不同而已:regasm /unregister "D:\My Documents\Visual Studio 2010\Projects\ExcelFunc\ExcelFunc\obj\Debug\ExcelFunc.dll"。