Недавно начал изучать язык программирования C и меня сразу заинтересовала такая тема, что можно написать для себя функции для использования в Excel'е. Вроде где-то читал, что функции, написанные на C/C++, быстро работают в Экселе по сравнению с VBA функциями, ну и решил написать простейшие функции для теста. На выходе мы получаем Win32 библиотеку (DLL), которую используем в Declare Function. Далее я узнал, что можно написать XLL надстройки, которые позволяют использовать функции С сразу в ячейках, а не в VBA, но это я не осилил, конечно. С улыбкой Если кто-то знает, есть ли разница в скорости работы VBA и функций, буду очень благодарен.0
На ваш суд выношу библиотеку с двумя функциями. Первая из них (addOne) совсем простая - прибавляет единичку к аргументу Double и возвращает результат.
Вторая функция - очень интересная. Если мне не изменяет память, этот вопрос задавал nerv - можно ли использовать VBA-функцию в качестве callback-функции. Ответ - с помощью C DLL можно!
Библиотеки сделал в двух вариантах - 32 и 64-х битные. Предпроцессорная директива (#If Win64) сама выберет нужную библиотеку. От вас требуется скопировать куда-нибудь эти две библиотеки и указать к ним полный путь после Lib. Файл с кодом я приложу.
Итак, сначала код VBA.
Итак, разберём, что к чему. Как я и говорил выше, директива #If Win64 автоматически загрузит нужную библиотеку - свою для 32 и 64-битного Офиса. Если вы не программировали Win32 API для 64-битного Офиса, то для 64-битного Офиса поменялись некоторые типы данных, которые необходимо использовать. Например, вместо Long - LongPtr и т.д. На моём примере мы видим для 64-битного Экселя "PtrSafe" и вместо Long используется LongPtr (так как указатели имеют длину не 32 бита (Integer - 4 байта)).
После того, как вы подправили путь к библиотеке, далее идут две тестовые процедуры (AddOneTest и AddOneUsingCallback) и вспомогательная функция (callback) для AddOneUsingCallback.
Первая простейшая C-функция - addOne в AddOneTest. Как видно, ничего нет сложного - вызываем функцию обычно как будто это VBA-функция. В примере в неё передаётся пятёрка, к ней прибавляется единичка, на выходе - 6.
Вторая C-функция - addOneWithCallback. Она имеем два аргумента. Первый - это адрес callback-функции, которая будет вызываться в C-функции. Второй аргумент я сделал для наглядности - он будет передаваться в VBA-функцию в C-библиотеке.
В комментариях я написал, что получается.
Итак, callback'и в VBA возможны. Думаю, Саша прочитает эту тему.
Исходный C код:
На ваш суд выношу библиотеку с двумя функциями. Первая из них (addOne) совсем простая - прибавляет единичку к аргументу Double и возвращает результат.
Вторая функция - очень интересная. Если мне не изменяет память, этот вопрос задавал nerv - можно ли использовать VBA-функцию в качестве callback-функции. Ответ - с помощью C DLL можно!
Библиотеки сделал в двух вариантах - 32 и 64-х битные. Предпроцессорная директива (#If Win64) сама выберет нужную библиотеку. От вас требуется скопировать куда-нибудь эти две библиотеки и указать к ним полный путь после Lib. Файл с кодом я приложу.
Итак, сначала код VBA.
| Код |
|---|
#If Win64 Then ' Excel 64-бит Private Declare PtrSafe Function addOne Lib "c:\DLLs\ExcelFuncs_x64.dll" _ (ByVal x As Double) As Double Private Declare PtrSafe Function addOneWithCallback Lib "c:\DLLs\ExcelFuncs_x64.dll" _ (ByVal funcPtr As LongPtr, ByVal x As Double) As Double #Else ' Excel 32-бит Private Declare Function addOne Lib "c:\DLLs\ExcelFuncs_x86.dll" _ (ByVal x As Double) As Double Private Declare Function addOneWithCallback Lib "c:\DLLs\ExcelFuncs_x86.dll" _ (ByVal funcPtr As Long, ByVal x As Double) As Double #End If Sub AddOneTest() MsgBox "Сумма = " & addOne(5) End Sub Sub AddOneUsingCallback() ' C-фукнция получает указатель VBA функции "AddOneCallback" и передаёт ей пятёрку. ' VBA функция прибавляет 1 к аргументу и возвращает 6. ' С функция возвращает в VBA шестёрку. MsgBox "5 + 1 = " & addOneWithCallback(AddressOf AddOneCallback, 5) End Sub Function AddOneCallback(ByVal x As Double) As Double AddOneCallback = x + 1 End Function |
Итак, разберём, что к чему. Как я и говорил выше, директива #If Win64 автоматически загрузит нужную библиотеку - свою для 32 и 64-битного Офиса. Если вы не программировали Win32 API для 64-битного Офиса, то для 64-битного Офиса поменялись некоторые типы данных, которые необходимо использовать. Например, вместо Long - LongPtr и т.д. На моём примере мы видим для 64-битного Экселя "PtrSafe" и вместо Long используется LongPtr (так как указатели имеют длину не 32 бита (Integer - 4 байта)).
После того, как вы подправили путь к библиотеке, далее идут две тестовые процедуры (AddOneTest и AddOneUsingCallback) и вспомогательная функция (callback) для AddOneUsingCallback.
Первая простейшая C-функция - addOne в AddOneTest. Как видно, ничего нет сложного - вызываем функцию обычно как будто это VBA-функция. В примере в неё передаётся пятёрка, к ней прибавляется единичка, на выходе - 6.
Вторая C-функция - addOneWithCallback. Она имеем два аргумента. Первый - это адрес callback-функции, которая будет вызываться в C-функции. Второй аргумент я сделал для наглядности - он будет передаваться в VBA-функцию в C-библиотеке.
Итак, callback'и в VBA возможны. Думаю, Саша прочитает эту тему.
Исходный C код:
| Код |
|---|
#define WINAPI __stdcall
// Указатель функции
typedef double (WINAPI *fptrAddNum)(double);
double WINAPI addOne(double x)
{
return x + 1;
}
double WINAPI addOneWithCallback(fptrAddNum callback, double x)
{
return callback(x);
} |
There is no knowledge that is not power