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

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

2 ответа

Решение

Я приведу простой пример того, как создать 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 в классе, как мы сделали бы это для класса в "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 * в типе параметра и "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

ошибка. Это связано с тем, что на VBA ссылаются (используют) на dll, который каким-то образом "владеет" ею, побуждая 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-dll для 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 слишком медленный - что неверно - и использовать что-то еще. Для этого я должен понизить ответ Говерта.;-)

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

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

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

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