Передача класса VBA, который реализует интерфейс ATL, в метод ATL

Редактировать:

У меня есть простой объект ATL MyATLObject, имеющий только один метод:

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

где toto - это функция шаблона, определяемая как

#pragma once

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

и где FCTPTR определяется как

typedef double (__stdcall * FCTPTR)( double);

Мой метод ATL использует двойной x для хранения результата toto и длинный AddressOfFunc, который является AddressOf функции VBA.

Эта передача функции VBA в методы ATL по адресу. это довольно ужасно. Как можно было бы сделать то же самое - передать функции VBA - методу ATL, в противном случае, например, определив интерфейс на стороне ATL?

Большое спасибо.

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

Первая версия моего вопроса:

На самом деле я делаю следующее: создаю проект ATL/COM, добавляя к нему "простой объект ATL" с именем MyATLObject:

1) в файле idl:

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++. Теперь я ссылаюсь на эту DLL в VBA и в VBA:

а) я определяю функцию

Public Function F(ByVal x As Double) As Double

    F = x * x - 2 * x + 1

End Function

б) и суб

    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) Выполнение этого подпункта даст мне в диапазоне V"alue_at_0" (здесь только ячейка) листа "Test1" значение в 0.0 функции F.

Я всегда работаю так: функция toto template здесь тривиальна (оценка на 0.0), но в целом это может быть процедура числовой интеграции или процедура поиска корня, для которой C++ необходим для быстроты; Я всегда передавал функции VBA через их адреса, благодаря ключевому слову VBA AddressOf: это дает мне длинную строку, которую я передаю методу ATL EVAL, я конвертирую эту длинную в указатель на функцию (FCTPTR) p и применяю свою процедуру "toto" to *p, что дает мне двойное значение, которое я возвращаю к своему методу ATL.

Это круто, все работает, но... Я нахожу это ужасным!!! И действительно не элегантный. Вот почему я хотел бы сделать следующее:

дизайн "как-то" интерфейс на стороне ATL,

interface IMyFunction : IDispatch

это будет реализовано (через реализации VBA) в VBA классом VBA VBAClass1 и передаст экземпляр этого класса VBA новой версии моего прежнего метода VBA для выполнения оценки в 0.0.

Моя проблема в том, что я не являюсь экспертом ни в ATL, ни в создании интерфейсов: мне удалось сделать действительно глупые / тривиальные вещи при создании интерфейса, хорошо, но я действительно не понимаю, как проектировать интерфейс что я хочу сделать, это:

интерфейс в ATL (который по определению будет иметь только методы, по конструкции ATL!), который будет иметь "что-то", играющее роль члена класса, член, отслеживающий функцию VBA, которую еще предстоит передать ему через ATL метод.

Любая помощь будет принята с благодарностью, ребята.

Я впервые здесь, так что извините за аванс, если сообщение не в идеальной / оптимальной форме.

Заранее спасибо.

Раф

1 ответ

Вы должны пересмотреть все, что у вас есть вокруг AddressOfFunc параметр и адрес обратного вызова. Когда вы разрабатываете интерфейс COM и хотите предоставить обратный вызов, вам нужно передать в качестве аргумента вызываемый указатель интерфейса COM в качестве аргумента ( соответствующее обсуждение), чтобы класс COM вызывал свои методы обратно - для этого вашему классу VBA необходим этот интерфейс ( связанный вопрос). Если вы предпочитаете не реализовывать интерфейсы на стороне VBA, другой вариант - создать COM-класс ATL с событиями ( точками подключения), чтобы класс COM вызвал событие, и ваш вызывающий обработчик выполнил бы его, выполнив действия обратного вызова.

Простой адрес функции здесь не сработает, вы должны были заподозрить его, когда вам приходилось разыгрывать вещи, чтобы они даже компилировались.

UPD. Это обеспечивает пример того, как отозвать код VB: Три способа реализовать обратный вызов VBScript (VB6, VBA) из класса C++/ATL

Другие вопросы по тегам