ATL COM, чтобы добавить функцию, чтобы преуспеть

Я пытаюсь создать ATL COM с классом C ++ и добавить его в Excel с помощью автоматизации. Я нашел несколько руководств, но у меня много проблем, одна из которых состоит в том, что мои dll не сравниваются в автоматизации, и если я пытаюсь добавить их, Excel говорит, что есть проблема, связанная с отсутствием сервера или отсутствием разрешений. Может ли кто-нибудь дать мне руководство? Я использую Visual Studio 2012. Спасибо.

3

Решение

Я приведу простой пример того, как создать c ++ ATL / COM dll, который будет ссылаться в Excel vba. DLL будет предоставлять VBA объект ATL / COM, и у этого объекта будет метод, который сможет взять двойное значение из Excel / vba, умножить его на 2,0 и вывести на VBA. Код VBA будет пригоден для определения функции Excel. Конечно, нет необходимости прибегать к dll c ++ для того, чтобы иметь функцию excel, умножающую содержимое ячейки на два, но это только для демонстрации.

Последнее замечание перед началом: лучше всего использовать Visual Studio (для краткости в этом ответе mvs) в качестве администратора для всего этого. Все версии MVS с 2005 года включены работы для этого.

Давайте начнем. откройте ваши любимые mvs, создайте новый проект: выберите шаблон «Проект ATL» в списке типов проектов шаблонов Visual c ++. Назовите его «MyATLProject» и выберите, чтобы сохранить его, например, в «C: \ Users … \ Desktop». Нажмите ОК Это откроет новое окно. Не нажимайте там на финише, а на следующем: теперь убедитесь, что отмечен только «dll», и если это так, нажмите на финиш. (Конечно, для нашей основной нужды нам здесь больше ничего не нужно.

Все, что мы сделали, создали решение (в «C: \ Users … \ Desktop \ MyATLProject», я называю $ (SOL) этот путь.) С двумя проектами в нем: MyATLProject & MyATLProjectPS. Законченный проект PS (PS означает прокси / заглушку) бесполезен для того, что мы хотим сделать, но в любом случае. Мы сделаем все здесь в отладке. Сделайте решение по перестройке. (Вы заметите, что MyATLProjectPS был пропущен из rebuid: это нормально.) Теперь вы можете видеть, что была создана папка $ (SOL) \ MyATLProject \ debug с различными файлами в ней, один из которых представляет для нас интерес. MyATLProject.dll -> это файл, на который мы будем ссылаться в VBA, и который мы выставляем нам объекты и методы. На данный момент, это ничего не даст нам в VBA, поскольку мы еще не реализовали ни ATL / COM-объект, ни тем более ни один метод.

Теперь давайте создадим объект ATL / COM. Есть трудный путь для этого и мягкий путь, я покажу только мягкий путь. Щелкните правой кнопкой мыши проект «MyATLProject» в обозревателе решений, затем «добавить», затем «класс», и в категориях выберите «ATL», а затем «Простой объект ATL». Затем нажмите «добавить». В простом имени введите «MyATLObject» и нажмите «Готово». (Здесь снова мы могли бы сделать больше, но для такого вступления нам не нужно больше.) Это создаст и откроет «MyATLObject.h» файл. MyATLObject.cpp также был создан, и MyATLProject.idl (присутствует в проекте поколения) был изменен. Эти три файла являются священной троицей для того, что мы намерены делать. Сделайте все ради ради. 😉 Был создан ATL / COM-объект MyATLObject без каких-либо методов. Вы могли бы видеть это VBA, если бы вы ссылались на DLL там, но будьте терпеливы, мы сделаем это позже.

Теперь давайте дадим метод этому объекту. Для этого есть трудный путь, и мягкий, я покажу вам обоим, сначала начнем с трудного. Первая модификация. Зайдите в MyATLProject.idl и замените

interface IMyATLObject : IDispatch{
};

от

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

Что мы наделали ? Файл idl «ссылается на наш MyATLObject«(Я добровольно неопределен) (а также другие объекты / интерфейсы, если это необходимо), и мы указываем в нем, что наши MyATLObject будет иметь метод с именем MULT, метод, который будет принимать ссылку (указатель на) double. Как вы можете догадаться, MULT умножит на 2,0 двойное значение Теперь мы должны соответственно изменить MyATLObject.h и MyATLObject.cpp. Вторая модификация : зайдите в MyATLObject.h и замените

public:

};

OBJECT_ENTRY_AUTO(__uuidof(MyATLObject), CMyATLObject)

в конце этого

public:

STDMETHOD(MULT)(DOUBLE* theDouble);
};

OBJECT_ENTRY_AUTO(__uuidof(MyATLObject), CMyATLObject)

Что мы наделали ? Мы объявили метод MULT в классе, как мы сделали бы это для класса в «ванили» 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 * в типе параметра и «theDouble» в имени параметра. Тот факт, что наш параметр является указателем DOUBLE * даст нам доступ к атрибутам параметров out и retval. Нажмите «in» а также «out«. Затем нажмите» Добавить «, а затем» Готово «. Это позволит воссоздать все, что мы сделали вручную (для MULT только и без его реализации конечно) раньше. Добавить

    *theDouble *= 2.0 ;

строка в реализации метода MULT в файле MyATLObject.cpp.

Предупреждение : в зависимости от версии mvs, по опыту может случиться так, что все будет воссоздано хорошо, кроме части файла idl, проверьте это, и если это так, сделайте это вручную, как мы делали это в первую очередь, во время жесткого путь.

Теперь пришло время использовать наши библиотеки ATL / COM c ++ в VBA Excel. Выберите свою любимую версию Excel и создайте электронную таблицу (в формате xlsm для более ранних версий Excel и в xls для поздней версии, потому что нам потребуются макросы) с именем MyATLProjectTEST.xls. Обязательно включите использование всех макросов. (Как это сделать, зависит от версии Excel, но вы узнаете, как это сделать с вашим другом Google.) Alt + F11, чтобы открыть VBA. Нажмите на инструмент, ссылки, перейдите к вашему MyATLProject.dll и нажмите, чтобы добавить ссылку на него. (Чтобы быть в безопасности, может быть, regsvr32 dll раньше -> это объясняется везде в Интернете, Google снова ваш друг по этому вопросу.) Вставьте модуль, он будет автоматически называться 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)

в ячейке B3, и наслаждайтесь результатом.

Примечание: попробуйте собрать решение в mvs, пока электронная таблица открыта: у вас будет

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

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

ошибка. Это потому, что dll упоминается (используется) в VBA, который каким-то образом «владеет» им, пытаясь заставить mvs модифицировать (перекомпилировать) его. При каждой модификации кода вам придется закрывать электронную таблицу для сборки / перестройки. Демо окончено.

Теперь самое интересное — отладочная сессия. Перестройте решение, снова откройте электронную таблицу и при необходимости измените ссылку на нее. Поместите точку останова на линию

*theDouble *= 2.0 ;

Выполните ctrl + alt + p (или «отладка», а затем «присоединить к процессу») в mvs, выберите таблицу Excel в списке и немного подождите, чтобы снова получить доступ к вашей таблице (на самом деле, пусть символы загружаются) , Теперь откройте VBA и установите точку останова на линии

Call o.MULT(x)

Теперь перейдите к ячейке B3 и пересчитайте ее. Вы сломаете VBA в указанной строке, и если вы войдете в (F8), вы сломаете в

*theDouble *= 2.0 ;

строка в MyATLObject.cpp.

Несколько последних замечаний.

1) DOUBLE * даже если это работает, это не правильный способ передачи информации из vba в c ++ и из c ++ в vba по следующей простой причине: вы продаете кому-то свой dll и vba-код, и он помещает строку LUDWIGVONMISES в B2 вместо помещения число. Что случилось бы ? Ошибка: выполняется в режиме «не отладка», который вы должны будете отслеживать в отладке, чтобы увидеть, где это происходит. Зачем ? Потому что вы не обрабатываете ошибки вообще. Для их обработки вы должны пройти VARIANT * между c ++ и VBA и работают в c ++, в начале вашего метода MULT, например, чтобы проверить, что VARIANT * указатель передан MULT указывает на VARIANT «упаковка» double и не string,

2)

Создание надстройки COM Automation — не лучший способ добавления пользовательских
Функции для Excel — это медленно и имеет различные ограничения. Лучше
сделать и т. д.

Будучи чрезвычайно сосредоточенным на времени выполнения кода, над которым я работаю и доставляю, и разработав множество ATL / COM-библиотек для Excel / VBA, а также xla / xll с использованием Excel SDK, Я совсем не согласен с этим заявлением от Говерта. Что можно сказать о небольшой демонстрации выше? Мы вошли в c ++, когда мы входим в метод MULT, и наш расчет (умножение на два) был сделан внутри метода. Это было быстро, но представьте, что вычисление, которое было сделано, было чем-то чрезвычайно интенсивным в числовом или в терминах памяти. Мы могли бы быть глупыми и делать это в нашем методе ATL / COM, но мы могли бы депортировать вычисления вне нашего метода, в простом c ++. Это было бы самым быстрым делом, и, на самом деле, это единственный разумный способ сделать это. То же самое, если вы хотите использовать Excel SDK, для непосредственного создания функций Excel, без переноса методов ATL / COM в код VBA для создания этих функций Excel, да. Здесь вы могли бы сказать: эй, тогда вариант xll с использованием Excel SDK лучше, потому что я не теряю время переноса. Возможно, но время переноса не так уж и велико, и с ATL / COM у вас есть VBA, где вы можете использовать ATL / COM-объект довольно элегантно, и вы можете использовать его для генерации com-объекта и т. Д. И т. Д. может даже получить доступ к памяти Excel для создания экземпляра объекта с помощью функций Excel, закодированных путем переноса метода ATL / COM в VBA! Более того, любая такая dll ATL / COM является ссылочной в проекте c # и может использоваться там так же, как вы используете ее в VBA. Даже в Яве. 😉 Это не относится к любому xla / xll, закодированному с помощью sdk в Excel, как к решениям, которые рекламирует Govert. Серьезное отсутствие возможности повторного использования.

3) ОП хочет использовать ATL COM, чтобы сделать что-то, что вполне выполнимо с ним, и Говерт говорит ему, что ATL / COM слишком медленный — что ложно — и использовать что-то еще. Для этого я должен понизить ответ Говерта. 😉

6

Другие решения

Создание надстройки COM Automation — не лучший способ добавления пользовательских функций в Excel — он медленный и имеет различные ограничения. Лучше сделать надстройку .xll на основе собственного C API (http://msdn.microsoft.com/en-us/library/office/bb687883.aspx). Если вы используете C ++, есть ряд наборов инструментов, которые очень помогают (использовать только SDK не так просто). Вы могли бы взглянуть на:

  • XLW — Оболочка с открытым исходным кодом для API, которая является стандартной отправной точкой
  • Библиотека Келла Льюиса xll — использует современные парадигмы C ++ с множеством примеров проектов.
  • XLL + — высоко ценимый коммерческий инструментарий с различными расширенными функциями, такими как асинхронные функции и интеграция с лентой.

Если вы предпочитаете использовать управляемый язык, такой как VB.NET, C # или F #, вы должны использовать открытый исходный код Excel-ДНК библиотека, которая позволяет интегрировать .NET с Excel, используя C API, а также имеет различные расширенные функции.

2