Передача структуры данных в DLL (stdcall)

Kukstyler

Хочу передать данные следующей структуры в DLL: Поле1: Символьный тип, длинной 15 букв (Pole_1: String[15]) Поле2: "Циферный" тип, длинной 5 цифр ИПоле3: Символьный тип, длинной 15 букв (Pole_1: String[15]) Поле4: "Циферный" тип, длинной 5 цифр Поле3 и Поле4 для того что бы DLL записал свои данные, которые я смогу прочитать в моей программе...Как мне указать длинну всех этих полей?
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    Edit2: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
  procedure CobCall (WS_CAMPO1: String; WS_CAMPO2: String); stdcall;
  external 'COB.DLL' name'COBPROG';
var
  Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
WS_CAMPO1: String;
WS_CAMPO2: String;
begin
WS_CAMPO1:=Edit1.Text;
CobCall (WS_CAMPO1,WS_CAMPO2);
Edit2.text:=WS_CAMPO2;
end;
 
end.
14 ответов

Kukstyler

И в каких случаях может быть "ACCESS VIOLATION"?


Kukstyler

Зависит от того как CobCall(WS_CAMPO1,WS_CAMPO2); определена. Если CobCall() обрабатывает оба своих параметра как нуль-терминальные строки (либо как указатель на массив символов с терминальным нулём), то всё отработает правильно. Вернее - нуль терминальная строка - под ней подразумевается указатель на массив символов. В конце этого массива должен располагаться симовол с кодом #0. Т. е. вызов можно уточнить так: CobCall(PChar(WS_CAMPO1), PChar(WS_CAMPO2)); Как описаны парметры CobCall() в твоей DLL?


Kukstyler

Зависит от того как CobCall(WS_CAMPO1,WS_CAMPO2); определена. Если CobCall() обрабатывает оба своих параметра как нуль-терминальные строки (либо как указатель на массив символов с терминальным нулём), то всё отработает правильно. Вернее - нуль терминальная строка - под ней подразумевается указатель на массив символов. В конце этого массива должен располагаться симовол с кодом #0. Т. е. вызов можно уточнить так: CobCall(PChar(WS_CAMPO1), PChar(WS_CAMPO2)); Как описаны парметры CobCall() в твоей DLL?
В CobCall данные описаны следующим образом: (DLL написан на COBOL-e)
[FONT=Courier New]01  LINK-AREA.[/FONT]
[FONT=Courier New]    05  INPUT-DATA.[/FONT]
[FONT=Courier New]        10  WS-CAMPO-1    PIC X(15).[/FONT]
[FONT=Courier New][/FONT] 
[FONT=Courier New]    05  OUTPUT-DATA.[/FONT]
[FONT=Courier New]        10  WS-CAMPO-2    PIC X(15).[/FONT]
Что в переводе с Кобола означает: LINK-AREA - Структуа данных (всех получаемых) INPUT-DATA - Структуа входных данных WS-CAMPO-1 - Символьная альфанумерическая строка длинной в 15 символов (15 байт, 1 байт по позиции/символу) OUTPUT-DATA - Структуа выходных данных WS-CAMPO-2 - Символьная альфанумерическая строка длинной в 15 символов (15 байт, 1 байт по позиции/символу)То есть я пытаюсь получить данные в WS-CAMPO-1, и поместить "ответ" в WS-CAMPO-2. Кстати, я не нашёл эквивалента COBOL Х(15) в Delphi. Для того что бы получить в DLL-е строку в 15 символов, мне приходется обявлять переменные как national - N(15) (2 байта на каждую позицию)... То же самое происходит с нумерическими строками... Если в COBOL-е я пишу S9(9) (signed-numeric 9 позиций, 1 байт на каждую позицию)...


Kukstyler

Кстати, я не нашёл эквивалента COBOL Х(15) в Delphi.
А как-то так
x:array[1..15]of byte;
или так
x:String(15);
x:ShortString(15);
не подойдет?


Kukstyler

С Array пока не пробовал, надо бы... Спасибо! А в случае c String, постоянно Access Violation...Дело в том что в COBOL-е тип и длинна каждой переменной указывается так:VA-TEXT PIC X(100) Х - означат альфанумерические символы, от А до 9, включая скобки, кавычки, точки и т.д. Длинна 100 символов, 100 байт. VA-NUM PIC 9(5) 9 означает цифровые символы, от 0 до 9, длинна 5 символов, от 00000 до 99999 VA-NUM-2 PIC S9(5)V99 S означает что переменна знаковая (+/-), V что после цифны идёт 2 децимальных разряда, то есть от -99999.99 до +99999.99 В обоих случаях, на каждую цифру 1 символ, 1 байт...Пока никак не смог создать такую же структуру в Дельфи... В любом случае выходит Access Violation, то есть передать данные кое-как выходит, не в том формате котором хочется но да, а вот посылая из COBOL DLL-а данные в LINK-AREA сразу Access Violation...


Kukstyler

Как я понял, в Cobol строка физически представлена в виде массива байтов. Но, видимо, в Delphi тип: String[15] не совместим с типом Cobol: PIC X(15). Потому что в Delphi переменная StrTmp : String[15] физически эквивалентна переменной: ArrTmp : array[0..15] of Char. Т. е. состоит из 16 байтов, а не из 15. При этом байт StrTmp[0] не относится к данным строки и относится к метаданным - т. к. содержит сведения о длине строки. Т. е. строку типа String[15] нельзя рассматривать как контейнер равноправных элементов (байтов). Из за этого, для вызова функции CobCall() видимо придётся использовать массив: ArrTmp : array[0..14] of Char; Причём, его индексы удобно прописать именно так: [0..14], потому что такие массивы Delphi умеет автоматически преобразовывать в строки. В общем вызов должен быть построен так:
type
  TArrChar  = array[0..14] of Char;
...
procedure CobCall (const WS_CAMPO1: TArrChar; var WS_CAMPO2: TArrChar); stdcall;
  external 'COB.DLL' name'COBPROG';
...
procedure TForm1.Button1Click(Sender: TObject);
var
  ArrChar1, ArrChar2  : TArrChar;
  StrRes              : String;
begin
  ...
  //Символьные массивы с нулевой нижней границей Delphi может обрабатывать как строки.
  ArrChar1 := 'Входные данные';
  ArrChar2 := '';
  CobCall(ArrChar1, ArrChar2);
  //Передаём данные в обыкновенную строку Delphi.
  StrRes := ArrChar2;
  ...
end;


Kukstyler

Ах да, в случае с цифровыми переменными, указывая емпакетацию COMP-3, переменная упаковывается в гексадецимальную систему, и занимает половину (по-парного) общего байтового размера, то есть если VA-NUM PIC 9(3) без эмпакетации занимает 3 байта, то VA-NUM PIC 9(3) COMP-3 занимает 2 байта, и в случае VA-NUM PIC 9(4) COMP-3 тоже 2 байта... Может это поможет принять цифровые данные в том виде которм надо получить их из Delphi?


Kukstyler

Kukstyler, как я понимаю, твоя программа на Delphi должна импортировать несколько функций из Cobol-Dll. Напиши как обявлены эти функции на Cobole и я распишу через какие типы данных и каким образом с ними работать на Delphi. Только напиши с такими же пояснениями, как ты выше написал - про внутреннее представление типов Cobol.


Kukstyler

Да не надо там ничего упаковывать. Делфи потом не поймет. С упакованными переменными работать - это гемор. Пробуйте читать по 2 байта как-то так
s:array[0..14] of SmallInt; - 2 байта
s:array[0..14] of ShortString[3]; - 3 байта.
И вроде короткая строка начинается с 0 до 2 И потом
StrToInt(s[0]);
и так для каждойТут надо понимать, что String - єто на самом деле динамический массив, а ShortString - статический. Поєтому там 0 єлемент либо занят либо отводится под данніе.Там есть SmallInt, ShortInt, Integer - 1, 2, 4 байта. А на 3 байта целочисленного типа нету


Kukstyler

Kukstyler, а есть какая-то дока по числовым типам данных Cobol, где было бы сказано - что, вот, например, в таком-то формате число соответствует стандарту IEE? Если такая инфа есть, то всё упрощается. С этого момента достаточно знать, что число соответствует IEE и занимает столько-то байт - этого достаточно. Если такой информации нет, то надо будет уточнить несколько моментов... --- Ребята, пишите пока, я сейчас до дома доберусь и опять на сайт зайду. Интересная тема.


Kukstyler

Kukstyler, как я понимаю, твоя программа на Delphi должна импортировать несколько функций из Cobol-Dll. Напиши как обявлены эти функции на Cobole и я распишу через какие типы данных и каким образом с ними работать на Delphi. Только напиши с такими же пояснениями, как ты выше написал - про внутреннее представление типов Cobol.
Я объясню зачем собственно всё это... COBOL программ много, по-этому я решил создать граф. интерфейс GUI на Delphi, передать данные COBOL DLL-у, и просто взять результат и отобразить в FORM, в EditField, StatiText... Ситуации бывают разные, но в итоге мне надо добиться уметь передать данные в правипьном формате которые будут введины в EditField Delphi Form. Для примера привиду следующую COBOL программу: Программа делает вычисление, для которого ей необходумо:
[FONT=Courier New]01  LINK-AREA.[/FONT]
[FONT=Courier New] 05  VXODAWIE-DANNIE.[/FONT]
[FONT=Courier New]     10  KOD       PIC 9(3).[/FONT]
[FONT=Courier New]     10  TIP       PIC X(4).[/FONT]
[FONT=Courier New]     10  NAZVANIE  PIC X(10).[/FONT]
[FONT=Courier New]     10  SUMMA     PIC S9(5)V99. [/FONT]
[FONT=Courier New]     10  SUMMA-2   PIC 9(4).[/FONT]
 
[FONT=Courier New] 05  OTVET-DANNYE.[/FONT]
[FONT=Courier New]     10  KLASS     PIC X(5).[/FONT]
[FONT=Courier New]     10  SUMMA-OUT PIC S9(5)V99. [/FONT]
Это структура создана для упрошения чтения программы, или удобного переноса данных. Вместо того что бы перенести все 5 полей из VXODAWIE-DANNIE по одному в спомогательные переменные программы, можно перенести их всех одним действием обращаясь к имени VXODAWIE-DANNIE. Но вся структура LINK-AREA эквивалентна этой:
[FONT=Courier New]01  KOD       PIC 9(3).            длинна: 3 цифровых позиций, 3 байта, беззнаковая[/FONT]
[FONT=Courier New]01  TIP       PIC X(4).            длинна: 4 альфанумерических позиций, 4 байта[/FONT]
[FONT=Courier New]01  NAZVANIE  PIC X(10).           длинна: 10 альфанумерических позиций, 10 байт[/FONT]
[FONT=Courier New]01  SUMMA     PIC S9(5)V99.        длинна: 5 цифровых позиций, знаковая, 2 децимальных позиции, 8 байт[/FONT]
[FONT=Courier New]01  SUMMA-2   PIC 9(4).            длинна: 4 цифровых позиций, 4 байта, беззнаковая[/FONT]
[FONT=Courier New]01  KLASS     PIC X(5).            длинна: 5 альфанумерических позиций, 5 байт[/FONT]
[FONT=Courier New]01  SUMMA-OUT PIC S9(3)V9.         3 цифровых позиций, знаковая, 1 децимальная позиция, 5 байт[/FONT]
Где:01 LINK-AREA - общая структура данных которые передаются с одной программы в другую (это просто условное название, хотя обращаясь к нему, обращаешся ко всем полям ниже уровня 01 (до следующего уровня равного 01-y) 05 VXODAWIE-DANNIE - общая структура входных данных , так же как и в прошлый раз, обращаясь к нему, обращаешся ко всем полям находящимся на уровне ниже 05 (до следующего уровня равного или выше 05-и. .... KLASS и SUMMA-OUT будут информированы в COBOL программе, после чего она возвращает контроль Delphi программе, которая берёт ответные данные и показывает их в EditField/StaticText своего FORM.
Kukstyler, а есть какая-то дока по числовым типам данных Cobol, где было бы сказано - что, вот, например, в таком-то формате число соответствует стандарту IEE? Если такая инфа есть, то всё упрощается. С этого момента достаточно знать, что число соответствует IEE и занимает столько-то байт - этого достаточно. Если такой информации нет, то надо будет уточнить несколько моментов... --- Ребята, пишите пока, я сейчас до дома доберусь и опять на сайт зайду. Интересная тема.
Ответ, если я правильно понял вопрос это ASCII.http://www.3480-3590-data-conversion.com/article-cobol-comp.htmlКстати, получая пустые поля в COBOL-e интерпретируются некими символами, или поля длинной 15 но где я ввёл данные только на 10 позиций, 10 позиций правильно передаются, остальные 5 вместо пустоты (SPACES, LOW-VALUE, NULLS), передают ещё какие-то непонятные символы...


Kukstyler

Ответ, если я правильно понял вопрос это ASCII. http://www.3480-3590-data-conversion...obol-comp.html
То что надо. Попробую написать функции для перевода Cobol данных в типы Delphi. В Delphi, кстати, типы соответствуют IEE соглашениям. Есть исключения, конечно - Real48, например - он для совместимости с прежними версиями.


Kukstyler

Ребята, а что-такое альфанумерическая позиция? Если не секрет


Kukstyler

Это аналог типа Char в Delphi - тип для хранения символов алфавита (AlphaBetic - алфавит по английски) + десятичные цифры (Numeric).