Я создал DLL, содержащую функцию с именем «koduj». Вызов этой функции с использованием ее в ячейке листа Excel возвращает желаемый результат. Вызов «кодуй» из VBA возвращает неправильный ответ.
Кодую нужны два аргумента: string nr_id
а также integer x1
, Рассчитывает сумму nr_id
буквы в ASCII представлении и добавляет x1
, Расчетная сумма возвращается.
Я следовал найденным инструкциям Вот.
Вот мой исходный файл .cpp:
#include<Windows.h>
#include<string>
using namespace std;//Convert BSTR to wstring for convenience
wstring BSTR_to_wstring (BSTR text){
return wstring(text, SysStringLen(text));
}
//Calculate sum of letters in ASCII representation
int ASCII_sum (wstring ws){
int sum = 0;
for (unsigned int i = 0; i < ws.length(); i++)
sum += ws[i];
return sum;
}
//"koduj" function
int _stdcall koduj (BSTR nr_id, int & x1){
wstring ws_nr_id = BSTR_to_wstring(nr_id);
return ASCII_sum(ws_nr_id) + x1;
}
Вот мое объявление функции VBA:
Declare Function koduj _
Lib "<dll_directory_and_full_name>" (ByVal x As String, ByRef y As Integer) As Integer
Написав:
=koduj("aaa";1)
Внутри ячейки листа я получаю желаемый результат (292)
Отладка этого кода VBA:
Sub test()
Dim a As Integer
a = koduj("aaa", 1)
End Sub
показывает неверный результат (а = 24930)
Я считаю, что мой код C ++ в порядке, так как он работает правильно при вызове из листа Excel.
Причина в том, что, хотя строки VBA являются внутренними UTF-16, VB всегда преобразует их в ASCII, прежде чем говорить с внешним миром (Declare
d функции, файл ввода / вывода). Итак, когда вы Declare
параметр As String
, VBA автоматически преобразует строка и передает его как ASCII. Соответствующий тип параметра на стороне C ++ должен быть LPSTR
или же LPCSTR
,
Если вы хотите использовать BSTR
на стороне C ++ вам также необходимо создать файл IDL для этой функции, скомпилировать его в TLB и ссылаться на TLB из VBA, только тогда VBA будет уважать и использовать BSTR
,
Другая проблема в том, что C ++ int
переводит на VBA Long
,
Причина, по которой он работает при вызове из листа Excel, заключается в том, что игнорирует правила VBA для преобразования строк. Я считаю, что это ошибка.
Попробуй объявить как долго:
Дим как долго
По величине ошибки я догадываюсь, что числовой параметр работает неправильно — я бы попытался более явно объявить тип параметра в вашей тестовой подпрограмме VBA (вероятно, Integer) и принять его как этот конкретный тип на стороне C ++ (подписанный Короче, в таком случае).
Есть отличная статья Microsoft обо всем этом на http://msdn.microsoft.com/en-us/library/office/bb687915(v=office.15).aspx.
Не предназначен для полного ответа, но тип вашего второго параметра выглядит неправильно.
Ваша функция DLL:
int _stdcall koduj (BSTR nr_id, int & x1)
объявляет x1
как ссылка (предположительно) 32-разрядное целое число.
Ваша декларация VBA:
Declare Function koduj Lib "<dll_directory_and_full_name>" (ByVal x As String, ByRef y As Integer) As Integer
объявляет у как указатель к 16-битный целое число.
Я бы посоветовал изменить объявление VBA следующим образом:
Declare Function koduj _
Lib "<dll_directory_and_full_name>" (ByVal x As String, ByVal y As Long) As Long
И, переключая вашу сигнатуру функции DLL, чтобы передать x1 по значению
int _stdcall koduj (BSTR nr_id, int x1)