Как создать dll для excel
Для начала создадим новый проект типа Class Library, назовем его cryptostar. Подключим библиотеку excel-dna:
Install-Package ExcelDna.AddIn
Install-Package ExcelDna.Integration
Install-Package ExcelDna.Interop
Первым делом напишем загрузчик данных:
Пояснять данный код я не буду, так как он довольно простой и к нашей теме отношение имеет довольно опосредованное.
Теперь мы умеем получать данные в виде массива объектов класса Ticker. Пришло время научиться отображать эти данные на текущей странице.
Что бы отобразить данные, нам понадобится экземпляр класса Microsoft.Office.Interop.Excel.Application. Он предоставляет доступ к объектной модели Excel, через него мы сможем получить объект-страницу(worksheet) и записать наши данные в нужные ячейки. Давайте напишем класс для записи данных на страницу.
При работе с объектной моделью надо помнить о том, что работаем со ссылками на COM объекты. В основном потоке Excel мы можем спокойно использовать эти объекты и не заботиться об освобождении ссылок (Marshal.ReleaseComObject), однако, если мы захотим использовать объектную модель из отдельного потока, у нас есть два варианта:
- Самостоятельно отслеживать все используемые объекты и очищать ссылки на них. Этот подход чреват ошибками и я не рекомендую его использовать.
- ExcelDna предоставляет возможность добавить задание на выполнение в основном потоке, для этого предназначен метод ExcelAsyncUtil.QueueAsMacro, пример использования:
Мы объявили кнопку, располагающуюся на закладке и группе с названием cryptostar. У кнопки задан обработчик onAction=’OnButtonPressed’, при нажатии на кнопку будет вызван метод OnButtonPressed в классе RibbonController.
Помимо обработчика мы указали изображение для кнопки: image=’bitcoin’. Имя изображения задается в конфигурационном файле — Cryptostar-AddIn.dna. Данный файл автоматически добавляется в проект при подключении nuget’a. Пример:
Сборка и Отладка
Наш плагин готов, давайте попробуем его собрать. Нажимаем F5. После чего получаем набор файлов *.xll:
Cryptostar-AddIn64-packed.xll, Cryptostar-AddIn-packed.xll, Cryptostar-AddIn.xll, Cryptostar-AddIn64.xll
Видим, что полученные файлы отличаются как по разрядности, так и по наличию слова packed. С разрядностью все понятно, выбирать нужно тот, который совпадает по разрядности с Excel. А чем же отличаются packed и не packed add-in'ы? ExcelDNA позволяет упаковывать зависимости плагина в .xll файл. Зависимостями могут являться любые файлы, используемые в проекте, например внешние библиотеки или картинки. Зависимости задаются в конфигурационном файле, выглядит это так:
Обратите внимание на атрибут Pack=”true”, он указывает, что данный файл должен быть упакован.
Если мы используем неупакованный add-in, то в одной директории с ним должны находиться и все его зависимости.
Теперь выбираем подходящий .xll файл и запускаем его. Если вы все сделали правильно, то после открытия Excel увидите новую вкладку Cryptostart и кнопку Get Data, а по нажатию на нее страница наполнится данными по валютам:
К сожалению, программы редко работают с первого раза, поэтому нам может потребоваться отладчик. Настроить отладку ExcelDna add-in'а просто. Для этого в свойствах проекта на закладке Debug выбираем Start External Program и прописываем путь к Excel.exe, в моем случае это G:\Program Files\Microsoft Office\Office14\Excel.exe. В start options пишем название упакованного файла add-in'a с учетом разрядности Excel. Например, Cryptostar-AddIn64-packed.xll. Все, теперь мы можем нажать F5 и полноценно отлаживать add-in.
Делаем установщик
Итак, add-in сделан, отлажен, протестирован и готов к работе. Вопрос в том, в каком виде его распространять. Один из вариантов доверить установку add-in'a пользователю. Делается это через интерфейс Excel, на закладке developer tab->Add-ins->Browse указываем путь к .xll файлу. Данный способ будет работать, только если .xll файл подписан сертификатом и сертификат присутствует в trusted root certification authorities store. Как создать сертификат и подписать им файл хорошо описано здесь.
Альтернативный способ – написать свою программу для установки add-in'a, которая бы прописывала необходимые ключи в реестре и таким образом регистрировала наш add-in. Задача эта не из легких, т.к. необходимо учитывать различные версии Excel у которых пути и ключи в реестре различаются. Но к счастью эта задача уже решена и существует шаблон проекта — инсталлятора, выполняющего необходимые действия. Шаблон можно взять здесь.
Заключение
В результате мы познакомились с библиотекой Excel-DNA и прошли полный путь от разработки add-in'a до его отладки и создания установщика.
Функции Excel4, Excel4v, Excel12 и Excel12v
Excel позволяет DLL получать доступ к командам и функциям через функции обратного вызова Excel4, Excel4v, Excel12 и Excel12v.
Функции Excel4 и Excel4v появились в версии Excel версии 4. Они работают со структурой данных XLOPER. В Excel 2007 появились две новые функции обратного вызова, Excel12 и Excel12v, которые работают со структурой данных XLOPER12. Функции Excel4 и Excel4v экспортируются библиотекой Xlcall32.lib, которая должна быть включена в проект DLL или XLL. Excel12 и Excel12v включены в исходный файл SDK C++ Xlcall.cpp, который должен быть в проекте, если вам нужен доступ к функциональным возможностям Excel с помощью структур XLOPER12.
Приведенный ниже код отображает прототипы для этих четырех функций. Первые три аргумента одинаковы с тем исключением, что второй аргумент является указателем на XLOPER в первой паре и указателем на XLOPER12 во второй. Соглашение о вызовах — _cdecl в Excel4 и Excel12 для разрешения списков переменных аргументов. Многоточие представляет указатели на значения XLOPER для Excel4 и значения XLOPER12 для Excel12. Количество указателей равно значению параметра count.
Все версии Excel
int _cdecl Excel4(int xlfn, LPXLOPER operRes, int count. );
int pascal Excel4v(int xlfn, LPXLOPER operRes, int count, LPXLOPER opers[]);
Начиная с Excel 2007
int _cdecl Excel12(int xlfn, LPXLOPER12 operRes, int count. );
int pascal Excel12v(int xlfn, LPXLOPER12 operRes, int count, LPXLOPER12 opers[]);
Чтобы DLL могла вызвать Excel4, Excel4v, Excel12 или Excel12v, приложение Excel должно передать управление библиотеке DLL. Это означает, что обратные вызовы API C возможны только в следующих ситуациях:
Из команды XLL, которую приложение Excel вызвало непосредственно или с помощью VBA.
Из листа XLL функции листа макросов, который приложение Excel вызвало непосредственно или с помощью VBA.
Невозможно вызвать API C Excel в следующих ситуациях:
Из события операционной системы (например, из функции DllMain).
Из фонового потока, созданного вашей DLL.
Возвращаемые значения
Все эти четыре функции возвращают целочисленное значение, которое уведомляет вызывающего о том, была ли функция или команда вызвана успешно. Могут возвращаться любые значения из указанных ниже.
Если вызов API C приносит результат либо xlretUncalced, либо xlretAbort, код DLL или XLL должен возвратить управление приложению Excel, прежде чем создавать другие вызовы API C (кроме вызовов функции xlfree, чтобы высвободить ресурсы памяти, выделенные приложению Excel, в значениях XLOPER и XLOPER12).
Аргумент перечисления команды или функции: xlfn
Аргумент xlfn — это первый аргумент для функций обратного вызова, он представляет собой 32-разрядное подписанное целое число. Его значение должно быть одним из перечислений функции или команды, определенным в файле заголовка SDK Xlcall.h, как показано в приведенном ниже примере.
Все функции листа и листа макросов находятся в диапазоне шестнадцатеричных чисел от 0 (xlfCount) до 0x0fff, хотя максимальное назначенное число в Excel 2013 является десятичным 547, шестнадцатеричным 0x0223 (xlfFloor_precise).
Все функции команды находятся в диапазоне шестнадцатеричных чисел от 0x8000 (xlcBeep) до 0x8fff, хотя максимальное назначенное число в Excel 2013 — шестнадцатеричное 0x8328 (xlcHideallInkannots). Они определяются в файле заголовка как (n | xlCommand) , где n — это десятичное число не меньше 0, а xlCommand определено как шестнадцатеричное число 0x8000.
Вызов команд Excel, которые работают с диалоговыми окнами
Некоторые коды команд соответствуют действиям в Excel, в которых используются диалоговые окна. Например, xlcFileDelete принимает один аргумент — маску или имя файла. Вызов можно выполнить с помощью диалогового окна, чтобы у пользователя была возможность отменить или изменить операцию удаления. Вызов возможен и без диалогового окна. В этом случае один или более файлов будут удалены без дальнейшего вмешательства при условии, что они существуют, а у вызывающего есть разрешение. Для вызова таких команд в формах диалогового окна перечисление команды должно объединяться с помощью битовой операции OR с 0x1000 (xlPrompt).
В показанном ниже примере кода удаляются файлы из текущего каталога, соответствующие маске my_data*.bak, а диалоговое окно отображается, только если аргумент верный.
Вызов функций и команд в международных версиях
Вы можете настроить в Excel вывод на экран имен функций и команд XLM на разных языках. Некоторые команды и функции API C работают со строками, которые будут интерпретироваться как имена функций или команд. Например, xlcFormula имеет аргумент строки, который предназначен для размещения в указанной ячейке. Чтобы надстройка работала со всеми языковыми параметрами, можно указать имена строк на английском и задать бит 0x2000 (xlIntl) в перечислении функций или команд.
В представленном ниже примере кода эквивалент =SUM(X1:X100) помещается в ячейку A2 на активном листе. Обратите внимание на то, что он использует функцию Framework TempActiveRef, чтобы создать временную внешнюю ссылку XLOPER. Формула будет отображаться в ячейке A2 на правильном языке, соответствующем региону (например, =SOMME(X1:X100) , если язык французский).
Так как результат вызова в Excel12 не требуется, нулевое значение (NULL) можно передать как второй аргумент вместо адреса xResult. Это обсуждается более подробно в следующем разделе.
Функции и команды только для DLL
Excel поддерживает небольшое количество функций, которые доступны только из DLL или XLL. Они определяются в файле заголовка как (n | xlSpecial) , где n — это десятичное число не меньше 0, а xlSpecial определяется как шестнадцатеричное число 0x4000. Эти функции перечислены в приведенной ниже таблице и задокументированы в справочнике по функциям API.
xlFree | 0 | xlSpecial | Освобождает ресурсы памяти, выделенные для Excel. |
xlStack | 1 | xlSpecial | Возвращает свободное место в стеке Excel. |
xlCoerce | 2 | xlSpecial | Преобразует тип XLOPER в XLOPER12 и наоборот |
xlSet | 3 | xlSpecial | Предоставляет быстрый метод для задания значений в ячейках. |
xlSheetId | 4 | xlSpecial | Получает имя листа от внутреннего идентификатора. |
xlSheetNm | 5 | xlSpecial | Получает внутренний идентификатор листа от его имени. |
xlAbort | 6 | xlSpecial | Проверяет, нажал ли пользователь кнопку ОТМЕНА или клавишу ESC. |
xlGetInst | 7 | xlSpecial | Получает дескриптор экземпляра Excel. |
xlGetHwnd | 8 | xlSpecial | Получает дескриптор главного окна Excel. |
xlGetName | 9 | xlSpecial | Получает путь и имя файла DLL. |
xlEnableXLMsgs | 10 | xlSpecial | Эта функция устарела, ее больше не нужно вызывать. |
xlDisableXLMsgs | 11 | xlSpecial | Эта функция устарела, ее больше не нужно вызывать. |
xlDefineBinaryName | 12 | xlSpecial | Определяет имя постоянного хранилища двоичных данных. |
xlGetBinaryName | 13 | xlSpecial | Получает данные имени постоянного хранилища двоичных данных. |
Возвращаемое значение XLOPER/XLOPER12: operRes
Аргумент operRes — это второй аргумент для обратных вызовов, который является указателем на XLOPER (Excel4 и Excel4v) или XLOPER12 (Excel12 и Excel12v). После успешного вызова он содержит значение, возвращаемое функцией или командой. В operRes можно задать нуль (указатель NULL), если возвращаемое значение не требуется. Предыдущее содержимое operRes будет перезаписано, чтобы вся ранее указанная память была освобождена перед вызовом во избежание утечки памяти.
Число последовательных аргументов: count
Аргумент count — это третий аргумент для обратного вызова, он представляет собой 32-разрядное подписанное целое число. Для него должно быть задано число последующих аргументов, начиная с 1. Если функция или команда не принимает аргументы, для него нужно задать ноль. В Microsoft Office Excel 2003 максимальное число аргументов, которое может принять функция, — 30, хотя большинство принимает меньше. Начиная с Excel 2007, максимальное число аргументов, которое может принять функция, увеличилось до 255.
count в Excel4 и Excel12 — это количество указателей на передаваемые значения XLOPER или XLOPER12. Нужно внимательно следить за тем, чтобы не передать меньше аргументов, чем заданное значение count. Это приведет к тому, что Excel прочтет стек преждевременно и попытается обработать недопустимые значения XLOPER или XLOPER12, что может привести к сбою приложения.
count в Excel4v и Excel12v — это размер массива указателей на значения XLOPER или XLOPER12, которые передаются как следующий и окончательный аргументы. Здесь также нужно внимательно следить за тем, чтобы не передать меньший массив, чем количество элементов count в размере, так как это приведет к переполнению границ массива.
Передача аргументов функции API C
Excel4 и Excel12 принимают списки аргументов переменной длины после count, которые интерпретируются как указатели на значения XLOPER и XLOPER12 соответственно. Excel4v и Excel12v принимают один аргумент после count, который является указателем на массив указателей на значения XLOPER в случае Excel4v, а также на значения XLOPER12 в случае Excel12v.
Формы массива Excel4v и Excel12v позволяют четко прописать в коде вызов API C, когда число аргументов меняется. В примере ниже показана функция, которая принимает массив чисел переменного раздела и использует функции листа Excel через API C, чтобы вычислить сумму, среднее, минимальное и максимальное.
Если в предыдущем коде заменить ссылки на значения XLOPER12 и Excel12v, указав XLOPER и Excel4v соответственно, функция будет работать во всех версиях Excel. Эта операция функций Excel SUM, AVERAGE, MIN и MAX достаточно проста, ее код было бы эффективнее написать на C, чтобы избежать чрезмерных затрат на подготовку аргументов и вызовы в Excel. Однако многие функции Excel более сложные, поэтому такой подход полезен в некоторых случаях.
В статье о xlfRegister приведен другой пример работы с Excel4v и Excel12v. При регистрации функции листа XLL можно указать описательную строку для каждого аргумента, который используется в диалоговом окне Вставить функцию. Число всех аргументов, переданных в xlfRegister, зависит от числа аргументов, которые принимает функция XLL, и меняется от функции к функции.
Если вы всегда вызываете функцию или команду API C с одним и тем же числом аргументов, вам лучше обойтись без дополнительного шага создания массива указателей для этих аргументов. В таких случаях проще и понятнее использование Excel4 и Excel12. Например, при регистрации функций и команд XLL нужно ввести полный путь и имя файла DLL или XLL. Можно получить имя файла в вызове xlfGetName, а затем передать его с вызовом в xlFree, как показано в приведенном ниже примере, посвященном Excel4 и Excel12.
На практике код функции Excel12v_example можно более эффективно написать путем создания одного аргумента xltypeMulti XLOPER12 и вызова API C с использованием Excel12, как показано в примере ниже.
В этом случае возвращаемое значение Excel12 игнорируется. Вместо этого код проверяет, является ли возвращаемое значение XLOPER12 xltypeNum, чтобы определить, выполнен ли вызов.
XLCallVer
Помимо обратных вызовов Excel4, Excel4v, Excel12 и Excel12v, Excel экспортирует функцию XLCallVer, которая возвращает версию API C, выполняемого в настоящий момент.
Прототип функции выглядит следующим образом:
int pascal XLCallVer(void);
Эту потокобезопасную функцию можно вызвать из любой команды или функции XLL.
В версиях Excel, начиная с Excel 97 и заканчивая Excel 2003, XLCallVer возвращает 1280 = 0x0500 шестн. = 5 x 256, что означает Excel версии 5. Начиная с Excel 2007, функция возвращает 3072 = 0x0c00 шестн. = 12 x 256, что означает версию 12.
Хотя ее можно использовать для определения доступности нового API C во время выполнения, иногда лучше определить текущую версию Excel с помощью Excel4(xlfGetWorkspace, &version, 1, &arg) , где arg является XLOPER с заданным числовым значением 2. Функция возвращает строку XLOPER, версию, которую можно привести к целому числу. Причина, по которой лучше полагаться на версию Excel, а не версию API C, заключается в том, что есть различия между Excel 2000, Excel 2002 и Excel 2003, которые вашей надстройке может понадобиться определять. Например, изменения точности некоторых статистических функций.
Создаем обычную динамическую библиотеку. Выбираем файл, создать, потом Win32 Dynamik-Link Library. Не забудьте указать имя проекта (DllExcel).
И три файла нужно создать в проекте. Как мы это делали в "Шаг 1 - Минимальный проект".
Создаем код
Описание и макрос Excel
Вот так работает наша DLL.
Описание
Первым шагом мы реализовали саму функцию в CPP файле. В общем всё тривиально, за исключением модификатора WINAPI. Существует несколько моделей вызовов функций. Для использования в Windows модель вызовов функций PASCAL. Для соответствия требованиям WIN32 API и добавлен модификатор. Дальше в exceldll.h мы описали данную функцию. Но применили опять модификатор для приведения имен функций к стандарту C. Применение этого стандарта гарантирует поддержку Ваших имен функций другими программами. Если DLL создается именно для вашего приложения, то это не важно, но если Вы собрались поделиться ей с миром, то должны обеспечить совместимость.
И последним шагом заполнили def файл, описав функцию MyTest как функцию экспорта, то есть что она будет извлекаться из DLL. Теперь собирайте проект. Полученную DLL нужно поместить в каталог Windows/System или просто Windows или WinNT, если Windows NT. При вызове функции из DLL необходимо чтобы DLL была найдена. В описанных каталогах операционная система обязательно посмотрит.
Теперь запустите Excel, создайте макрос, опишите функцию и код макроса. Пояснений я сюда писать не буду, т.к. это касается программирования VBA. А если вы этого не умеете, зачем вам этот шаг, хотя на Бейсике программировать может каждый. Запускайте макрос. Если Вы всё сделали правильно, то увидите диалоговое окно созданное функцией DLL.
Это очень хорошая возможность. Применив данную технику Вы можете расширить возможности любой программы, которая имеет макроязык и функции работы с DLL. Перечислю на взлет программы Microsoft Office, Corel Draw (Corel Script), AutoCad (VBA), ArcView (Avenue) и т.д.
Всем привет!
Подскажите, пожалуйста, а то я не догоняю что я делаю не так.
Я не силен в "ООП", поэтому прошу помощи у профессионалов.
- Как прописать вызов функции из excel без указания параметров, так как нужно чтобы эта функция не возвращала значение, а работала с ячейками?
- Как из DLL определить нужную книгу (ту из которой была вызвана эта DLL)?
- Как передаются массивы?
- Почему excel не видит DDL?
Вот например короткий код и как я это пишу, что не правильно?
Это в DLL Проект1 в Класс1:
Добавлено через 2 часа 48 минут
Мега мозги, помогите пжл.!
Помощь в написании контрольных, курсовых и дипломных работ здесь
Создание dll для динамического подключения в EXCEL без регистрации
Доброго времени суток! Дорогие друзья, переработал большой объем информации из интернета, но.
Как зарыть файл без сохранения (Excel/VBA )?
Как закрыть .xls без сохранения, чтобы не выскакивало окно с вопросом о сохранении изменений в.
Как сохранить VBA-массив в CSV-файл без Excel
Как можно сохранить VBA-массив в CSV-файл без использования Excel? Сейчас я сначала вставляю.
Как создать файл DLL так, чтобы его можно было подключить к VBA Excel?
Пытаясь научиться подключать к VBA хотя бы самую тривиальную функцию на C++. Для примера написал.
Вопрос задан двусмысленно: если развернуто он звучит так "вызов функции, расположенной в DLL, из Excel", то
если развернуто он звучит так: "вызов функции из Excel, если эта функция является функцией Excel", то Вам сюда
Программирование с использованием C API в Excel
Только если Вы передадите книгу (или ее имя, если нужно только определить) как параметр (по ссылке).
Куда? Если в функцию, то минимально затратно - по ссылке.
Судя по строкам 4,5,7,8 и т.д. в Вашем верхнем коде, если Вы записали его в редакторе VBA и он не выделил написанное красным, то прекрасно видит.Если же Вы про свой код
то, простите меня, это не DLL. И еще "печалька" - на VBA DLL не создать - это интерпретируемый язык.
так не вызвать.
Если "DLL Проект1 в Класс1" у Вас в одном проекте с "Это в excel", попробуйте набрать Класс1.FnVoz1, правда что делает весь Ваш код я не знаю.
Сорри, может я коряво изложил вопрос.
Я спрашивал как например вызвать функцию, которую я перенес из excel в DLL (VB6) - FnVoz1()?
FnVoz1()- эта функция, которая делает некоторые манипуляции в книге excel и она написана мною для примера и
показана в примере (что она делает), а так же у нее нет аргументов (параметров для передачи обратно), т.е. она просто
выполняет какие то действия с объектом excel из которого она была вызвана.
Так вот, мне не понятно, почему excel ругается, что не может найти эту функцию, хотя DLL лежит в одной папке вместе с excel из которого она вызывается. пишет что DLL не найдена (ошибка 53)
И правильно ли я пишу в DLL обращение обратно в excel, а так же принцип написания кода при обращении к ячейкам excel из Dll?
Хотя я DLL даже подключал в ручную через Tools->References.
Добавлено через 2 минуты
Я пробовал через Класс1.FnVoz1, так он другую ошибку выдает, complite error: Variable not defined
выделяет класс1
. Вы не сделаете этого без использования API Excel (не API Windows)
Мда. не увидел, и что у Вас вот-такие выражения скомпилировались в VB6
т.е Excel.ShTab.Cells(2, intColum + 1).Select- так нельзя в VB6 писать?
. а все дальнейшие строки-обращения в этом примере обрабатывает уже не этот код, а экземпляр приложения Excel: при компиляции примера на VB6 эти строки будут "переведены" в вызовы API Excel, которые будет принимать и выполнять экземпляр приложения Excel. То есть в памяти компьютера будет "висеть" и Ваше приложение - транслятор и приложение Excel. Вам это нужно было? Зачем тогда это делать на VB6 если можно оставить на VBA? На практике это необходимо, если Вам нужны возможности VB6, отсутствующие в VBA, или когда Ваше приложение вообще делает что-то другое и ему просто понадобились вычислительные возможности Excel. но тогда тему лучше перенести-создать в соответствующем языку программирования разделе форума.
Читайте также: