ATL COM为excel添加一个函数

我试图build立一个C ++类的ATL COM,并通过自动化添加到Excel。 我发现了一些指南,但我有很多问题,其中一个是我的DLL没有在自动化比较,如果我尝试添加它Excel的说有没有包含服务器或没有权限的问题。 有人能给我一个指导吗? 我正在使用Visual Studio 2012.谢谢。

我将给出一个简单的例子,说明如何创build一个c ++ ATL / COM dll,这个dll可以在Excel的vba中引用。 该DLL会暴露给VBA一个ATL / COM对象,这个对象将有一个方法,将从excel / vba中取一个double,并将其乘以2.0并输出到VBA。 VBA代码将可用于定义一个excel函数。 当然,不需要求助于一个c ++ dll,因为excel的function是将一个单元格的内容加两个,但是这只是为了演示。

开始之前的最后一句话: 更好地运行visual studio(在整个这个答案中称为mvs简称)作为pipe理员的所有这一切。 所有2005版本的mvs都包含这个function

让我们开始吧。 打开你最喜欢的mvs,创build一个新的项目:在Visual c + +模板项目types列表中select模板“ATL项目”。 将其命名为“MyATLProject”,并select将其保存在“C:\ Users … \ Desktop”中。 点击确定。 这将打开一个新的窗口。 不要单击完成,但在下一步:现在检查只有“DLL”被选中,如果是这样,点击完成。 (当然,对于我们的基本需求,我们不需要在这里。

我们所做的所有事情都创build了一个解决scheme(在“C:\ Users … \ Desktop \ MyATLProject”中,我调用$(SOL)这个path。)有两个项目:MyATLProject和MyATLProjectPS。 PS结束的项目(PS代表代理/存根)对于我们想要做的事情是无用的,但无论如何。 我们将在这里做一切debugging。 做一个重build解决scheme。 (你会注意到MyATLProjectPS已经从重新跳过了:这是正常的。)现在你可以看到一个文件夹$(SOL)\ MyATLProject \ debug已经被创build,其中包含了各种文件,我们感兴趣的是MyATLProject.dll – >这个文件是我们必须在VBA中引用的那个文件,而且我们暴露了我们的对象和方法。 就目前而言,它在VBA中对我们没有任何意义,因为我们还没有实现任何ATL / COM对象,更没有任何方法。

现在,让我们创build一个ATL / COM对象。 对于这个和软的方法有一个很难的方法,我只会显示出柔和的方式。 右键单击解决scheme资源pipe理器中的“MyATLProject”项目,然后“添加”,然后“类”,并在类别中select“ATL”,然后“ATL简单对象”。 然后点击“添加”。 在简单的名字把“MyATLObject”,然后点击完成。 (这里我们可以做更多,但是对于这样的介绍,我们不需要更多。)这将创build并打开一个“ MyATLObject.h ”文件。 MyATLObject.cpp也被创build,并且MyATLProject.idl (出现在项目世代)已被修改。 这三个文件是我们打算做的事情的圣洁三位一体。 为了缘故,重build一切。 ;-)现在已经创build了ATL / COM对象MyATLObject,现在没有任何方法。 你可以看到VBA,如果你要参考那里的DLL,但要耐心,我们会在稍后做。

现在,让我们给这个对象一个方法。 对于这个和软的方法有一个困难的方法,我会告诉你们两个,首先从硬的方面开始。 第一次修改 。 进入MyATLProject.idl并replace

interface IMyATLObject : IDispatch{ }; 

通过

 interface IMyATLObject : IDispatch{ [id(1), helpstring("method MULT")] HRESULT MULT([in,out] DOUBLE* theDouble); }; 

我们做了什么 ? idl文件“引用我们的MyATLObject ”(我自愿模糊)(以及其他对象/接口,如果需要的话),我们指定我们的MyATLObject将有一个方法称为MULT ,方法将采取引用)双。 正如你所猜测的, MULT将乘以2.0所指向的双倍数。 现在,我们必须相应地修改MyATLObject.h和MyATLObject.cpp。 第二次修改 :转到MyATLObject.h并replace

 public: }; OBJECT_ENTRY_AUTO(__uuidof(MyATLObject), CMyATLObject) 

在它的结尾

 public: STDMETHOD(MULT)(DOUBLE* theDouble); }; OBJECT_ENTRY_AUTO(__uuidof(MyATLObject), CMyATLObject) 

我们做了什么 ? 我们已经在类中声明了MULT方法,就像我们为“vanilla”c ++中的类所做的那样。 第三次和最后一次修改 :转到MyATLObject.cpp和之后

 // CMyATLObject 

 STDMETHODIMP CMyATLObject::MULT(DOUBLE* theDouble) { return S_OK; } 

S_OKHRESULTtypes,并通过返回告诉我们的MULT方法是否完成。 (这里不需要更详细的了解我们在这里计划的内容)现在我们必须真正实现MULT方法,比如像这样(我自愿地在这里丑陋和不安全,以后你会自己去devise):

 STDMETHODIMP CMyATLObject::MULT(DOUBLE* theDouble) { *theDouble *= 2.0 ; return S_OK; } 

重build解决scheme。 ATL / COM对象MyATLObject现在已经更新,现在有一个方法MULT 。 这是(实际上)添加一个方法的困难方式。 软的方法是使用向导:撤消所有的三个修改我们做的和重build,以便我们现在在我们正在joinMULT方法时,我们在同一阶段。 转到类视图,展开MyATLProject,右键单击界面IMyATLObject (带有图标的图标,图标看起来像一个小键),点击“添加”,然后“添加方法”。 这将打开添加方法向导。 将MULT放在方法名称中,在参数types中selectDOUBLE *在参数名称中select“theDouble”。 事实上,我们的参数是一个指针DOUBLE *会给我们访问out和retval参数的属性。 点击“ in ”和“ out ”。 然后点击添加,然后完成。 这将重新创build我们手工完成的所有操作(仅适用于MULT ,并且不需要执行)。 添加

  *theDouble *= 2.0 ; 

在MyATLObject.cpp文件中执行MULT方法。

警告 :根据mvs版本的不同,根据经验,可能会发生除idl文件部分之外的所有事情都被重新创build,检查它,如果是这样的话,就像我们在第一时间做的那样手工完成艰辛的道路。

现在是时候在excel的VBA中使用我们的ATL / COM c ++ dll了。 select你最喜欢的Excel版本,并创build一个名为MyATLProjectTEST.xls的电子表格(xlsm格式用于早期的excel版本,xls用于迟到的版本,因为我们将需要macros)。 确保启用所有的macros。 (如何做到这一点与Excel的版本不同,但你会发现如何与你的朋友谷歌做。)Alt + F11打开VBA。 单击工具,引用,浏览到您的MyATLProject.dll,然后单击以添加对其的引用。 (为了安全起见,也许regsvr32的DLL之前 – >这是在互联网上到处解释,谷歌是你的朋友在这一次。)插入一个模块,它会自动被称为模块1。 其中,代码:

 Public Function MULT(x As Double) As Double Dim o As MyATLProjectLib.MyATLObject Set o = New MyATLProjectLib.MyATLObject Call o.MULT(x) MULT = x End Function 

现在放在电子表格的一张表格中,放在B2单元格中,然后放入公式

 =MULT(B2) 

在B3单元格,并享受结果。

备注:在电子表格打开时,尝试在mvs中构build解决scheme:您将拥有一个

 Error 1 Could not delete file 'c:\users\...\desktop\myatlproject\myatlproject\debug\MyATLProject.dll'. 

确保该文件不被另一个进程打开,并且不受写保护。 MyATLProject

错误。 这是因为dll在VBA中被引用(使用),他们以某种方式“拥有”它,通过empeaching mvs来修改(重新编译)它。 每次修改代码时,您都必须closures电子表格以进行构build/重build。 演示结束。

现在,“乐趣”部分,debugging会话。 重build解决scheme,重新打开电子表格,如果需要的话,重新引用它的DLL。 把一个断点就行了

 *theDouble *= 2.0 ; 

在mvs中执行ctrl + alt + p(或“debug”,然后“attach to process”),在列表中selectexcel电子表格,然后等待一段时间再次访问电子表格(实际上让符号加载) 。 现在打开VBA并在该行放置一个断点

 Call o.MULT(x) 

现在转到B3单元格,并重新计算它。 你将在指定的行中打破VBA,如果你步入(F8),你将在这个行程中断开

 *theDouble *= 2.0 ; 

在MyATLObject.cpp中。

最后的一些言论。

1) DOUBLE *即使它工作不正确的方式来传递信息从VBA到C ++和从C ++到VBA,原因如下:你卖你的DLL和VBA代码给某人,他把一个stringLUDWIGVONMISES在B2而不是放一个数字。 会发生什么 ? 一个错误:在一个“非debugging”模式下,你必须在debugging中跟踪,看看它发生了什么。 为什么? 因为你根本不处理错误。 为了处理它们,你应该在c ++和VBA之间传递VARIANT * ,并且在你的MULT方法开始的时候以c ++的方式运行,以检查传递给MULTVARIANT *指针指向一个VARIANT “包装”一个double一个string

2)

制作COM自动化加载项不是将用户定义的函数添加到Excel的最佳方式 – 速度慢并且具有各种限制。 最好是做等等

对于我正在处理和交付的代码,我已经非常专注于执行时间,并且为excel / VBA开发了很多ATL / COM dll,以及使用excel sdk的xla / xll, 我完全不同意这一点Govert声明。 关于上面的小演示,我们可以说些什么? 当我们inputMULT方法时,我们已经input了c ++,我们的计算(乘以2)在方法内部完成。 这很快,但是想象一下,所做的计算在数值上或内存方面是非常密集的。 我们可能是愚蠢的,并在我们的ATL / COM方法中做,但我们可以在我们的方法之外,以普通的c ++recursion计算。 这将是最快的做法,而afaik,这是唯一合理的做法。 同样的事情,如果你想使用Excel的SDK,直接生产Excel函数,而不包装ATL / COM方法的VBA代码来产生这些Excelfunction是的。 在这里你可以这样说:嘿,使用excel sdk的xll选项会更好,因为我不会浪费包装时间。 也许,但包装的时间真的不是那么大,用ATL / COM,你有你的VBA,在那里你可以用相当优雅的方式使用ATL / COM对象,你可以用它来生成com对象等等。甚至可以访问excel内存,通过在VBA中打包ATL / COM方法编码的excel函数实例化对象。 而且,任何这样的ATL / COM dll都可以在C#项目中引用,并且可以像在VBA中一样使用。 即使在java中。 😉这不是用excel的sdk编码的任何xla / xll,就像Govert所宣传的解决scheme一样。 严重缺乏可重用性的担忧。

3)OP希望使用ATL COM来做一些完全可行的事情,而Govert告诉他ATL / COM太慢了 – 这是错误的 – 并且使用别的东西。 为此,我应该倒戈弗特的答案。 😉

制作COM自动化加载项不是将用户定义的函数添加到Excel的最佳方式 – 速度慢并且具有各种限制。 更好的办法是根据本地C API( http://msdn.microsoft.com/en-us/library/office/bb687883.aspx )制作一个.xll插件。 如果您使用的是C ++,则有许多工具包可以帮助您(仅使用SDK并不那么容易)。 你可能想看看:

  • XLW – API的开放源码包装,是标准的起点
  • 基思·刘易斯的xll库 – 使用现代C ++范例,以及各种示例项目。
  • XLL + – 备受好评的商业工具包,具有各种高级function,如asynchronousfunction和function区集成。

如果您更喜欢使用托pipe语言,比如VB.NET,C#或F#,则应该使用开放源代码的Excel-DNA库,该库允许使用C API将.NET与Excel集成,还具有各种高级function。