Обращение к DLL (fpc) из VBA(excel)

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Обращение к DLL (fpc) из VBA(excel)

Сообщение azsht » 15.04.2013 15:09:16

При выполнении макроса при обращении к test
выдается сообщение:
run-time error "49"
bad DLL calling convention

Если параметры не массивы, все работает.
Ниже привожу исходники.
Спасибо



<<----------------- ЭТО FPC ----------------------------->>
unit testU;
interface
procedure test(var tabl1: array of double); export; stdcall;
implementation
procedure test(var tabl1: array of double); stdcall;
var
i: integer;
begin
for i := 0 to 7 do tabl1[i] := i;
end;
exports test;
end.

<<----------------- ЭТО VBA ----------------------------->>
Private Declare Sub test Lib "test.dll" (ByRef tabl1() As Double)
Sub TWS()
Dim tabl1(0 To 7) As Double
MsgBox (tabl1(6))
Rem Call tab1(T, tabl1)
Call test(tabl1)
MsgBox (tabl1(6))
End Sub
azsht
незнакомец
 
Сообщения: 5
Зарегистрирован: 15.04.2013 14:58:44

Re: Обращение к DLL (fpc) из VBA(excel)

Сообщение bormant » 15.04.2013 15:38:44

Полагаю, с массивами нужно поступать по образу и подобию: http://support.microsoft.com/kb/207931/en-us
Аватара пользователя
bormant
постоялец
 
Сообщения: 408
Зарегистрирован: 21.03.2012 11:26:01

Re: Обращение к DLL (fpc) из VBA(excel)

Сообщение azsht » 15.04.2013 15:42:10

А обойтись без SAFEARRAY никак нельзя?
azsht
незнакомец
 
Сообщения: 5
Зарегистрирован: 15.04.2013 14:58:44

Re: Обращение к DLL (fpc) из VBA(excel)

Сообщение NTFS » 15.04.2013 16:58:49

Мой бог... ну не пишут на Паскале dll для использования в сторонних программах. Язык программирования Windows - это С и Assembler. Вот и пишите на них. Иначе не сейчас, так потом проблемы вылезут.

Вот работающий код из моего приложения-расширения для Excel. Сможете перевести это в Паскаль - будет хорошо.

Код: Выделить всё
// GetTime.cpp: определяет экспортированные функции для приложения DLL.
//

#include "stdafx.h"

#pragma comment(linker, "/export:CalcArray=_CalcArray@4")
#pragma comment(linker, "/export:CalcSum=_CalcSum@40")
#pragma comment(linker, "/export:CalcMax=_CalcMax@40")
#pragma comment(linker, "/export:CalcMin=_CalcMin@40")
#pragma comment(linker, "/export:CalcSred=_CalcSred@40")

typedef struct
{
WORD rows;
WORD columns;
double array[1]; // Start of array[rows * columns]
}
xl_array;

extern "C" __declspec(dllexport) double __stdcall CalcSum(double n1,double n2,double n3,double n4, double n5)
{
  return(n1+n2+n3+n4+n5) ;
}

extern "C" __declspec(dllexport) double __stdcall CalcMax(double n1,double n2,double n3,double n4, double n5)
{
  double r = n1 ;
  if (n2>r) r = n2 ;
  if (n3>r) r = n3 ;
  if (n4>r) r = n4 ;
  if (n5>r) r = n5 ;
  return(r) ;
}

extern "C" __declspec(dllexport) double __stdcall CalcMin(double n1,double n2,double n3,double n4, double n5)
{
  double r = n1 ;
  if (n2<r) r = n2 ;
  if (n3<r) r = n3 ;
  if (n4<r) r = n4 ;
  if (n5<r) r = n5 ;
  return(r) ;
}

extern "C" __declspec(dllexport) double __stdcall CalcSred(double n1,double n2,double n3,double n4, double n5)
{
  double cnt = 5 ;
  return((n1+n2+n3+n4+n5)/cnt) ;
}

extern "C" __declspec(dllexport) double __stdcall CalcArray(xl_array *p_array)
{
if(!p_array || !p_array->rows
|| !p_array->columns || p_array->columns > 0x100)
return (123) ;
int size = p_array->rows * p_array->columns;
double sum ;
for(int i = 0; i < size; i++)
  sum=sum+p_array->array[i] ; //= i / 10.0;
return(sum) ;
}
NTFS
постоялец
 
Сообщения: 388
Зарегистрирован: 05.11.2007 14:57:50
Откуда: Краснодар

Re: Обращение к DLL (fpc) из VBA(excel)

Сообщение alexey38 » 15.04.2013 20:05:57

NTFS писал(а):Мой бог... ну не пишут на Паскале dll для использования в сторонних программах. Язык программирования Windows - это С и Assembler. Вот и пишите на них. Иначе не сейчас, так потом проблемы вылезут.

Не нужно говорить ерунду. На паскале пишут все, что угодно. Просто не нужно программирование воспринимать как шаманство, особенно, когда идет взаимодействие между различными языками. Вначале разбираемся, что требует смежная система, и затем реализуем аналогичное в паскале.

Добавлено спустя 3 минуты 5 секунд:
bormant писал(а):Полагаю, с массивами нужно поступать по образу и подобию: http://support.microsoft.com/kb/207931/en-us

Здесь рассмотрено несколько вариантов. В любом случае нужно понимать, что паскалевские динамические массивы, как и паскалевские строки - это специальные элементы со счетчиком элементов и счетчиком ссылок, и невозможно гарантировать одинаковость структуры заголовков.

Добавлено спустя 1 минуту 42 секунды:
azsht писал(а):А обойтись без SAFEARRAY никак нельзя?

Можно, если не нужно создавать массив внутри DLL. SAFEARRAY нужен для того, чтобы выделить память под динамический массив в DLL, передать ее в головную программу и там освободить память. SAFEARRAY определяет общий алгоритм выделения/освобождения памяти, и одинаковую для всех структуру самого массива.

Добавлено спустя 1 минуту 15 секунд:
NTFS писал(а):Вот работающий код из моего приложения-расширения для Excel. Сможете перевести это в Паскаль - будет хорошо.

Данный код без каких либо проблем переводится на паскаль.
alexey38
долгожитель
 
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Re: Обращение к DLL (fpc) из VBA(excel)

Сообщение NTFS » 15.04.2013 20:32:24

alexey38
На паскале пишут все, что угодно.


Правильнее будет так: на паскале можно написать все, что угодно. Проблема в том, что это может и работать, как угодно.
Есть четкие целевые назначения языков. Делать системные задачи на Паскале - так же неудобно, как и оболочку базы данных на C.
NTFS
постоялец
 
Сообщения: 388
Зарегистрирован: 05.11.2007 14:57:50
Откуда: Краснодар

Re: Обращение к DLL (fpc) из VBA(excel)

Сообщение alexey38 » 15.04.2013 20:46:37

NTFS писал(а):Есть четкие целевые назначения языков. Делать системные задачи на Паскале - так же неудобно, как и оболочку базы данных на C.

Это выдумка маркетологов и не более. Паскаль как язык полностью равнозначен (только лучше) тому же самому "С". И во времена турбопаскаля и доса мы прекрасно писали всякие там резидентные проги не только на ассемблере, но и на паскале. Все аналогично и сегодня. Единственное, что сам компилятор не позволяет компилировать в дрова, но вопрос не о дровах (драйверах).

Поэтому не нужно выдумывать, что у языков есть "четкие целевые назначения". Есть SDK и библиотеки, которые существуют под конкретные языки, что делают не очень простым путь реализации аналога на другом языке (под который нет SDK).
Занимаясь системным программированием нужно понимать, как работает система, какие функции можно использовать, а какие нельзя. При этом нужно хорошо знать и свой язык программирования, понимать, что можно использовать, а что нельзя. Все просто и однозначно, и ни как не связано с языком "С".

Тем более, что интеграция с бейсиком никогда не называлась системной задачей. Тут просто вначале нужно изучить сам вопрос взаимодействия разных систем и разных приложений, а затем начинать реализовывать.
А когда нужно наоборот управлять извне тем же самым Excel, Word или подобным, то паскаль (в его Дельфовской реализации) является идеальным инструментом по причине удачной реализации COM, OLE, Variant. На С-ях это самоубийство, хоть и родная среда для винды. Собственно Микрософт так долго тянул лямку с бейском, по причине корявости языка "С" и "С++" при работе с технологиями COM, OLE, Variant.
alexey38
долгожитель
 
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Re: Обращение к DLL (fpc) из VBA(excel)

Сообщение azsht » 16.04.2013 09:23:58

приятно, что мой примитивный вопрос вызвал дискуссию, но может быть кто-нибудь подскажет, что неправильно в приведенном мной коде
azsht
незнакомец
 
Сообщения: 5
Зарегистрирован: 15.04.2013 14:58:44

Re: Обращение к DLL (fpc) из VBA(excel)

Сообщение NTFS » 16.04.2013 10:02:35

azsht

Вам уже подсказали.
Вариант 1: Выкинуть код на Паскале, поставить бесплатный Visual Studio Express, потом сделать по примерам из официальных руководств по автоматизации Excel.
Вариант 2: Найти рабочий вариант кода на C++ и перевести все на Паскаль, разобравшись, какие типы в С++ соответствуют типам в Паскаль.

alexey38
Это выдумка маркетологов и не более. Паскаль как язык полностью равнозначен (только лучше) тому же самому "С"


Паскаль как язык почти идентичен тому же С. Только вместо begin end идут скобки, да оператор if можно заменить на ?:.
Только на языке программирования ничего не напишешь, да. Потому что уже операции ввода-вывода для языка - это нужны различные SDK. А бинарный код, в который переводится язык - это работа компилятора.
Потому я и говорю: да, на Паскале можно сделать драйвер устройства, а на чистом C сделать морду к базе. Только зачем?
NTFS
постоялец
 
Сообщения: 388
Зарегистрирован: 05.11.2007 14:57:50
Откуда: Краснодар

Re: Обращение к DLL (fpc) из VBA(excel)

Сообщение alexey38 » 16.04.2013 10:55:47

azsht писал(а):приятно, что мой примитивный вопрос вызвал дискуссию, но может быть кто-нибудь подскажет, что неправильно в приведенном мной коде

Ошибка в строке
Код: Выделить всё
procedure test(var tabl1: array of double); stdcall;

Собственно Ваш вывод "Если параметры не массивы, все работает." говорит о том, что внутренняя структура массивов в паскале не соответствует внутренней структуре массивов в байсике.

Добавлено спустя 39 минут 45 секунд:
Как реализовать, то смотрите либо MSDN, либо пример от NTFS, его структура xl_array прекрасно реализуется в паскале.

Добавлено спустя 6 минут 26 секунд:
NTFS писал(а):Потому я и говорю: да, на Паскале можно сделать драйвер устройства, а на чистом C сделать морду к базе. Только зачем?

Драйвер на паскале не нужно писать, тут согласен. Но взаимодействие с бейсиком, Excel, Word и т.п. - это как раз ниша паскаля, а не С++. У паскаля код работает очень ожидаемо, нет ни какого шаманства. Поэтому в паскале очень легко реализуется взаимодействие между разными системами. Но взявшись за решению данной задачи нужно вначале изучить предметную область.
Например, Ваш пример функции:
Код: Выделить всё
extern "C" __declspec(dllexport) double __stdcall CalcArray(xl_array *p_array)

Если его переписать:
Код: Выделить всё
extern "C" __declspec(dllexport) double __stdcall CalcArray(std::string *p_array)
, то он не будет работать, как и не работает код на паскале:
Код: Выделить всё
procedure test(var tabl1: array of double); stdcall;

Языки программирования и наличие SDK тут не причем.
alexey38
долгожитель
 
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Re: Обращение к DLL (fpc) из VBA(excel)

Сообщение Widowmaker » 16.04.2013 20:22:57

Код: Выделить всё
type TRealVector = array of double;
procedure test(const size_of_tabl1: longint; var tabl1: TRealVector); export; stdcall;

( cпособ "мешок с биркой"; остальные навороты вроде cdecl ни к чему )
Аватара пользователя
Widowmaker
новенький
 
Сообщения: 37
Зарегистрирован: 27.04.2011 18:32:04

Re: Обращение к DLL (fpc) из VBA(excel)

Сообщение azsht » 17.04.2013 09:12:14

Widowmaker писал(а):type TRealVector = array of double;
procedure test(const size_of_tabl1: longint; var tabl1: TRealVector); export; stdcall;

А как при этом выглядит обращение из VBA к test?
azsht
незнакомец
 
Сообщения: 5
Зарегистрирован: 15.04.2013 14:58:44

Re: Обращение к DLL (fpc) из VBA(excel)

Сообщение Widowmaker » 17.04.2013 14:35:31

Я не большой знаток VBA, но, думаю, как-то так:

Код: Выделить всё
<<----------------- ЭТО FPC ----------------------------->>
library testU;
//
{$mode objfpc} {$H+}
//
type TRealVector = array of double;
//
procedure test(const size_of_tabl1: longint; var tabl1: TRealVector); export; stdcall;
var
i: integer;
//
begin
for i := 0 to size_of_tabl1 - 1 do tabl1[i] := i;
end;
//
exports test;
//
begin
end.

<<----------------- ЭТО VBA ----------------------------->>
Option Explicit
Option Base 0
'
Private Declare Sub test Lib "test.dll" (ByRef size_of_tabl1 as Long, ByRef tabl1() As Double)
'
Sub TWS()
'
Dim size_of_tabl1 As Long
Dim tabl1() As Double
'
size_of_tabl1 = 8
ReDim tabl1(0 To size_of_tabl1)
'
MsgBox (tabl1(6))
'
Rem Call tab1(T, tabl1)
'
Call test(size_of_tabl1, tabl1)
'
MsgBox (tabl1(6))
'
End Sub
Аватара пользователя
Widowmaker
новенький
 
Сообщения: 37
Зарегистрирован: 27.04.2011 18:32:04

Re: Обращение к DLL (fpc) из VBA(excel)

Сообщение azsht » 19.04.2013 12:30:16

Собрал работающий код:

VBA
Private Declare Sub test Lib "test.dll" (ByRef tabl1() As Double)
Sub TWS()
Dim tabl1(0 To 7) As Double
MsgBox (tabl1(6))
Call test(tabl1)
MsgBox (tabl1(7))
End Sub

Delphi
unit testU;
interface
uses ActiveX,SysUtils;
procedure test(var tabl1: PSafeArray); stdcall;
implementation
procedure test(var tabl1: PSafeArray); stdcall;
var
b: PDouble;
i,i1,i2: integer;
begin
SafeArrayGetLBound(tabl1, 1, i1);
SafeArrayGetUBound(tabl1, 1, i2);
SafeArrayAccessData(tabl1, b);
for i := i1 to i2 do b[i] := i+0.4;
SafeArrayUnaccessData(tabl1)
end;
exports test;
end.

Всем спасибо!
azsht
незнакомец
 
Сообщения: 5
Зарегистрирован: 15.04.2013 14:58:44

Re: Обращение к DLL (fpc) из VBA(excel)

Сообщение Alex2013 » 25.04.2013 16:23:38

Как вариант можно использовать не ДЛЛ а просто программу в простейшем варианте выдающую результат на консоль или в файл . Или чуть сложнее организовывать обмен через кипборд ДДЕ а можно вообще через сокеты по tcp/ip ... Общем вариантов много и что особенно удобно почти нет нужды совмещать несовместимые форматы данных и программа работает как-бы самостоятельно что облегчает ее отладку .
Alex2013
долгожитель
 
Сообщения: 3138
Зарегистрирован: 03.04.2013 11:59:44


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 14

Рейтинг@Mail.ru