ATL COM将函数添加到excel中

ATL COM to add a function to excel

本文关键字:excel 添加 函数 COM ATL      更新时间:2023-10-16

我正试图用c++类构建一个ATL COM,并通过自动化将其添加到excel中。我找到了一些指南,但我有很多问题,一个是我的dll在自动化方面无法比较,如果我尝试添加它,excel会说存在不包含服务器或没有权限的问题。有人能给我一个导游吗?我使用的是Visual Studio 2012。谢谢

我将给出一个简单的例子,说明如何创建一个可在Excel的vba中引用的c++ATL/COM dll。dll将向VBA公开一个ATL/COM对象,该对象将具有一个方法,该方法可以从excel/VBA中获得一个双精度,将其乘以2.0并输出到VBAVBA代码可用于定义excel函数。当然,不需要使用c++dll来实现excel函数将单元格的内容增加两倍,但这只是为了演示。

开始前的最后一句话:最好运行visualstudio(在整个答案中简称mvs)作为所有这些的管理员。2005年的所有版本的mvs都包含了这方面的工作

让我们开始吧打开您喜爱的mvs,创建一个新项目:在Visual c++模板项目类型列表中选择模板"ATL项目"。将其命名为"MyATLProject",并选择将其保存在"C:\Users…\DesDesktop"中。单击"确定"。这将打开一个新窗口。不要点击完成,而是点击下一步:现在检查是否只检查了"dll",如果是,点击完成。(当然,为了我们的基本需求,我们这里不需要更多了

我们所做的一切都创建了一个解决方案(在"C:\Users…\Desktop\MyATLProject"中,我将$(SOL)称为此路径。)其中有两个项目:MyATLProject&MyATL项目PS。PS结束的项目(PS代表代理/存根)对我们想要做的事情毫无用处,但无论如何。我们将在这里进行调试。执行重建解决方案。(您会注意到,MyATLProjectPS已从rebid中跳过:这很正常。)现在您可以看到,已经创建了一个文件夹$(SOL)\MyATLProject\debug,其中有各种文件,我们感兴趣的是MyATLPproject.dll-->该文件是我们必须在VBA中引用的文件,我们将向我们公开对象和方法。目前,它不会在VBA中向我们公开任何内容,因为我们还没有实现任何ATL/COM对象,更不用说任何方法了。

现在,让我们创建一个ATL/COM对象这有一条艰难的道路,也有一条柔软的道路,我只会展示柔软的道路。右键单击解决方案资源管理器中的"MyATLProject"项目,然后"add",然后"class",在类别中选择"ATL",然后选择"ATL simple object"。然后点击"添加"。在简单的名称中放入"MyATLObject",然后单击finish。(在这里,我们可以做更多,但对于这样的介绍,我们不需要更多。)这将创建并打开一个">MyATLObject.h"文件MyATLObject.cpp也已创建,并且MyATLProject.idl(在项目生成时存在)已被修改。这三份文件是我们打算做的神圣的三位一体。看在上帝的份上重建已经创建了一个ATL/COM对象MyATLObject,目前没有任何方法。如果你想在那里引用dll,你可以在VBA中看到它,但请耐心,我们稍后会做。

现在,让我们给这个对象一个方法这有一种艰难的方式,也有一种温和的方式,我会向你们展示,先从艰难的方式开始第一次修改。进入MyATLProject.idl并替换

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和MyATLOobject.cpp。第二次修改:转到MyATLOObject.h并替换

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_OK的类型为HRESULT,如果我们的MULT方法完成得好或不好,则通过返回告诉。(我们在这里的计划不需要更详细。)现在我们必须真正实现MULT方法,比如这样(我在这里自愿丑陋和不安全,你稍后会自己设计):

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

重建解决方案。ATL/COM对象MyATLObject现在已经更新为具有方法MULT。这是为了(事实上不是很难)添加一个方法。软方法是使用向导:撤消我们所做的所有三个修改并重新构建,这样我们现在就处于与添加MULT方法时相同的阶段。进入类视图,展开MyATLProject,右键单击界面IMyATLObject(有手柄图标的,图标看起来像一个小键),单击"添加",然后单击"添加方法"。这将打开添加方法向导。在方法名称中输入MULT,在参数类型中选择DOUBLE *,在参数名称中选择"Double"。事实上,我们的参数是一个指针DOUBLE *,这将使我们能够访问out和retval参数属性。单击"in"answers"out"。然后单击"添加",然后单击"完成"。这将重现我们以前手工完成的所有操作(仅针对MULT,当然没有实现)。添加

*theDouble *= 2.0 ;

MyATLObject.cpp文件中MULT方法实现中的行。

警告:根据mvs版本的不同,根据经验,可能会发生除了idl文件部分之外的所有内容都被很好地重新创建的情况,请检查它,如果是这种情况,请像我们最初在艰难的过程中那样手动执行。

现在,是时候在excel的VBA中使用我们的ATL/COM c++dll了选择您最喜欢的excel版本,并创建一个名为MyATLProjectTEST.xls的电子表格(早期excel版本为xlsm格式,后期版本为xls格式,因为我们需要宏)。确保启用所有宏。(如何做到这一点因excel的版本而异,但你可以在朋友谷歌上找到。)Alt+F11打开VBA。单击工具,引用,浏览到您的MyATLProject.dll,然后单击添加对它的引用。(为了安全起见,可能是regsvr32之前的dll-->这在互联网上到处都有解释,谷歌再次是您的朋友。)插入一个模块,它将自动被称为Module1。其中,代码:

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

现在,在电子表格的表格中,把3.14159放在B2单元格中,然后把公式

=MULT(B2)

并享受结果。

备注:当电子表格打开时,尝试在mvs中构建解决方案:您将有一个

Error   1   Could not delete file         'c:users...desktopmyatlprojectmyatlprojectdebugMyATLProject.dll'.

请确保该文件未被其他进程打开,并且没有写保护。MyATL项目

错误。这是因为dll在VBA中被引用(使用),VBA以某种方式"拥有"它,并委托mvs修改(重新编译)它。每次修改代码时,您都必须关闭电子表格以进行构建/重建演示结束

现在,"有趣"的部分,调试会话重建解决方案,重新打开电子表格,并在需要时重新引用其中的dll。在线上设置断点

*theDouble *= 2.0 ;

在mvs中执行ctrl+alt+p(或"调试",然后"附加到进程"),在列表中选择excel电子表格,等待一段时间,以便再次访问电子表格(事实上,让符号加载)。现在打开VBA并在行放置断点

Call o.MULT(x)

现在转到单元格B3,并重新计算它。您将在指定的行中断VBA,如果您进入(F8),您将中断

*theDouble *= 2.0 ;

MyATLObject.cpp.中的行

最后几句话

1)DOUBLE *即使有效,也不是将信息从vba传递到c++和从c++传递到vba的正确方式,原因很简单:你把你的dll和vba代码卖给了某人,他在B2中放了一个字符串LUDWIGVONMISES,而不是放一个数字。会发生什么?一个错误:在"非调试"模式下,您必须在调试中跟踪它,以查看它发生在哪里。为什么?因为您根本不处理错误。为了处理它们,您应该在c++和VBA之间传递VARIANT *,并在c++中操作,例如,在MULT方法的开头,检查传递给MULTVARIANT *指针是否指向"包装"doubleVARIANT,而不是string

2)

制作COM自动化外接程序不是添加用户定义的最佳方式函数转换为Excel-速度很慢并且有各种限制。更好制作etc

我非常关注我正在编写和交付的代码的执行时间,并且已经为excel/VBA开发了许多ATL/COM dll,以及使用excel-sdk的xla/xll,我完全不同意Govert的这一说法关于上面的小演示,我们能说些什么?当我们输入MULT方法时,我们已经输入了c++,并且我们的计算(乘2)是在该方法中完成的。这很快,但想象一下,所做的计算在数值上或在记忆方面是非常密集的。我们可能很愚蠢,在ATL/COM方法中进行计算,但我们可以用纯c++将计算导出到方法之外。这将是最快的方法,当然,这是唯一合理的方法。如果你想使用excel-sdk直接生成excel函数,而不需要在VBA代码中包装ATL/COM方法来生成这些excel函数,也是一样的。是的。在这里你可以说:嘿,使用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正在宣传的解决方案一样严重缺乏可重用性问题

3) OP希望使用ATL/COM来做一些完全可行的事情,而Govert告诉他ATL/COM太慢了——这是错误的——不能使用其他东西。为此,我应该否决戈弗特的回答

制作COM Automation外接程序并不是将用户定义的函数添加到Excel的最佳方式,它速度慢,而且有各种限制。更好的方法是在本机C API的基础上制作一个.xll插件(http://msdn.microsoft.com/en-us/library/office/bb687883.aspx)。如果你正在使用C++,那么有很多工具包会帮你很多忙(只使用SDK并不那么容易)。你可能想看看:

  • XLW-API的开源包装器,它是标准的起点
  • Keith Lewis的xll库使用了现代C++范式,并提供了各种各样的示例项目
  • XLL+-一个备受推崇的商业工具包,具有各种高级功能,如异步功能和功能区集成

如果您更喜欢使用托管语言,如VB.NET、C#或F#,则应使用开源Excel-DNA库,该库允许使用C API将.NET与Excel集成,并且还具有各种高级功能。