2012-08-07 73 views
1

编辑:传递实现的ATL接口VBA类,到ATL方法

我有一个ATL简单对象MyATLObject,仅具有一个方法:

STDMETHODIMP CMyATLObject::EVAL(DOUBLE* x, long AddressOfFunc) 
{ 
*x = toto<FCTPTR>(*((FCTPTR) AddressOfFunc)) ; 
return S_OK; 
} 

其中托托是一个模板功能由

#pragma once 

template<typename F> 
double toto(F f) 
{ 
    return f(0.0) ; 
} 

定义且其中FCTPTR被定义为

的typedef双(__stdcall * FCTPTR)(双);

我ATL方法消耗用于存储TOTO的结果双x和长AddressOfFunc其为VBA函数的AddressOf。

这传递VBA函数ATL方法的地址。这是相当可怕的。如何才能做到这一点 - 将VBA函数传递给ATL方法,否则,例如通过在ATL端定义一个接口?

非常感谢。

////////////////////////////////////////////// ////////////////////////////////////////////////// ////////////////////////////////////////////////// ////////////////////////////////////

第一版我的问题:

我实际上做以下操作:创建一个ATL/COM项目,添加名为MyATLObject “简单ATL对象” 将其与:在IDL文件

1):

interface IMyATLObject : IDispatch{ 
[id(1), helpstring("method EVAL")] HRESULT EVAL(DOUBLE* x, long AddressOfFunc) ; 
}; 

2在MyATLObject.h文件:

一个

#include "MyStupidEvaluator.h" 

typedef double (__stdcall * FCTPTR)(double); 

类的外部,并在类

public: 
STDMETHOD(EVAL)(DOUBLE* x, long AddressOfFunc) ; 

和最后在MyATLObject.cpp文件中:

STDMETHODIMP CMyATLObject::EVAL(DOUBLE* x, long AddressOfFunc) 
{ 
*x = toto<FCTPTR>(*((FCTPTR) AddressOfFunc)) ; 
return S_OK; 
} 

MyStupidEvaluator.h包含:

#pragma once 

template<typename F> 
double toto(F f) 
{ 
    return f(0.0) ; 
} 

这仅仅是一个模板函数,在任何函数对象的零返回值,即一个接纳()算子类型名(或类) 。

现在,这给了我,编译后,一个dll。

这是所有C++的一部分。现在,我在VBA和VBA引用此DLL:

一)我定义一个函数

Public Function F(ByVal x As Double) As Double 

    F = x * x - 2 * x + 1 

End Function 

b)和子

Public Sub Draft1() 

     Dim ENGINE As MyTestProjectLib.MyATLObject 
     Set ENGINE = New MyTestProjectLib.MyATLObject 
     Dim x As Double 
     x = 0# 

     Call ENGINE.EVAL(x, AddressOf F) 
     Sheets("Test1").Range("Value_at_0").Offset(0, 0).Value = x 

    End Sub 

c)执行这一分将给对我来说,在工作表“Test1”的范围V“alue_at_0”(这里只是一个单元格)中,功能F的值为0.0。

我总是这样工作:toto模板函数在这里是微不足道的(在0.0评估),但在一般来说它可能是一个数值积分例程,或者是一个为了快速而需要C++的寻根程序;我是通过他们的地址传递VBA函数的,这要归功于AddressOf VBA关键字:这给了我很长的一段时间,我传递给了我的ATL方法EVAL,我将这个long函数指针(FCTPTR)p转换,并且将我的例程“ toto“to * p,这给了我一个双倍的回报,我回到我的ATL方法。

这很酷,一切正常,但...我觉得这太可怕了!而且非常不雅。这就是为什么我要做到以下几点:

设计“莫名其妙”的对ATL侧接口,

interface IMyFunction : IDispatch 

,将在VBA用VBA类VBAClass1来实现(通过VBA的器具),并将该VBA类的实例传递给我以前的VBA方法的新版本,以便在0.0处执行评估。我的问题是:我不是ATL的专家,也不是在界面创建:我成功地在界面创建中做了真正的愚蠢/微不足道的事情,好吧,但我真的不知道如何去做设计接口做我想做的事情,那就是:

ATL中的一个接口(根据定义,它只有通过ATL构造的方法!),它具有扮演类的成员角色的“东西” ,会员跟踪VBA功能仍然需要通过ATL方法传递给他。

任何帮助将不胜感激,乡亲们。

这是我第一次来这里,如果消息不是完美/最佳的形式,那么很抱歉。

预先感谢您。

拉斐

回答

0

你应该重新考虑一切你身边AddressOfFunc参数和回调地址。当你设计COM接口并且你想提供一个回调函数时,你需要传递一个可调用的COM接口指针作为参数(related discussion),以便COM类可以调用它的方法 - 这需要你的VBA类实现这个接口( related question)。如果您不想在VBA端实现接口,另一种方法是设计带有事件(connection points)的ATL COM类,以便COM类可以触发一个事件,并且调用者会在那里执行回调活动。

功能的普通地址在这里不起作用,当你不得不抛出一些东西来编译它们时,你应该怀疑它。

UPD。这提供了如何回调VB代码的示例:Three ways to implement VBScript (VB6, VBA) callback from C++/ATL class

+0

谢谢你的回答。我仍然是一个新手,所以我没有真正明白你的意思:正如我所解释的,我确实希望传递一个可调用的接口指针作为参数,是的,因此我在问我该如何设计它接口,因为我现在无法自己回答这个问题,对ATL几乎一无所知。 – 2012-08-07 14:29:46

+0

例如,在我的情况下,你将如何设计界面? – 2012-08-07 15:06:35

+0

我提到的情景,这是可行的。我没有显示的代码段,对不起。关于这两者的第一个建议 - 你将在ATL项目中定义回调接口(在IDL中),你可以找到[如何在VBA中实现这个接口](http://stackoverflow.com/questions/3171324/implementing- my-own-interface-in-vba-error-object-module-needs-to-implement)就在这里。 – 2012-08-07 16:51:16