Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Не получить корректный Record по указателю из С++ DLL / 25 сообщений из 47, страница 1 из 2
13.01.2021, 20:52
    #40035572
Kast2K
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
Добрый день, коллеги!

Дельфи 10.3.3

Есть железяка и DLL от производителя.
Описание вызова:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
#include "fwlib32.h" or "fwlib64.h"

FWLIBAPI short WINAPI cnc_diagnoss(unsigned short FlibHndl, short number, short axis, short length, ODBDGN *diag);

length   [ in ]

Specify the data block length(size of ODBDGN structure).

    4+(byte size of diagnosis data) * (number of axis) 

typedef struct  odbdgn {
   short datano;              /* diagnosis data number */
   short type;                /* upper byte:type */
                              /* lower byte:axis */
   union {
      char  cdata;            /* bit/byte diagnosis data */
      short idata;            /* word diagnosis data */
      long  ldata;            /* 2-word diagnosis data */
      char  cdatas[MAX_AXIS]; /* bit/byte diagnosis data with axis*/
      short idatas[MAX_AXIS]; /* word diagnosis data with axis */
      long  ldatas[MAX_AXIS]; /* 2-word diagnosis data with axis */
   } u ;
} ODBDGN ;



Основываясь на C# примере (с диска производителя)
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
		void Button2Click(object sender, EventArgs e)
		{
			short a = Convert.ToInt16(textBox10.Text); //308		
			
		//	ConnectionID=32769;
			ODBDGN oo = new ODBDGN();
			string ss="";
			short b = 8; // (-1);

			status = cnc_diagnoss(ConnectionID,a,b,12,oo); //4+1*8
 			foreach (byte qq in oo.cdatas)
			{
				 ss = ss+ qq.ToString();
			}
			textBox1.Text = textBox1.Text + String.Format("Data : {0}\n\r\n\rValues : {1}\n\r\n\r",oo.datano,ss);
		}



получаю результат как на экране железяки, например, 75 68 65 68 0 0 0 0

пытаюсь получить тоже самое в Delphi

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
const
  MAX_AXIS=8;

  Podbdgn = ^Todbdgn;
  Todbdgn=packed record
    datano:SmallInt;
    dtype:SmallInt;

    LDATAS: array[0..MAX_AXIS-1] of byte;
  end;

function cnc_diagnoss (FlibHndl:Word; number: SmallInt; axis: SmallInt; length :SmallInt; diag:Podbdgn):SmallInt;stdcall;external 'Fwlib32.dll';

procedure TForm2.Button1Click(Sender: TObject);
var
  i:Integer;
  h:Word;
  odData:Podbdgn;
  odD:Todbdgn;
  ip:AnsiString;
  s:string;
begin
  h:=0;
  try
    try

      ip:='10.*.*.*';
      i:=cnc_allclibhndl3(PAnsiChar(ip),45001,5, @h);
      Memo1.Lines.Add('i='+i.ToString);

      if (i=0) then
        begin
          Memo1.Lines.Add('cd found');
          New(odData);
          ShowMessage(sizeof(odD).ToString);

          i:=cnc_diagnoss(h, smallint(seNum.Value), SmallInt(MAX_AXIS), {SmallInt(4+(4*(MAX_AXIS-1)))}sizeof(odD), odData);
          Memo1.Lines.Add('cd i='+i.ToString);

          Memo1.Lines.Add(odData^.datano.ToString +'|'+odData^.dtype.ToString{+'|'+odData^.ldata.ToString});
          for I := 0 to MAX_AXIS-1 do
            begin
                s:=odData^.LDATAS[i].ToString;
                Memo1.Lines.Add(i.ToString+':='+s);
            end;
          Dispose(odData);
        end;
    except on E: Exception do
      Memo1.Lines.Add('ERROR='+e.Message);
    end;

  finally
    if h<>0 then
      begin
        cnc_freelibhndl(@h);
        Memo1.Lines.Add('Fanuc closed success');
      end;
  end;
end;



В результате вижу следующее:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
i=0
cd found
cd i=0
308|8
0:=81
1:=0
2:=0
3:=0
4:=84
5:=111
6:=112
7:=116
Fanuc closed success



Предположил, что проблема в длине принимаемого массива внутри union. Изменил:
Код: pascal
1.
LDATAS: array[0..MAX_AXIS-1] of byte; -->>LDATAS: array[0..MAX_AXIS-1] of LongInt;



Результат:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
i=0
cd found
cd i=0
308|8
0:=72
1:=10
2:=6553699
3:=6684704
4:=7667823
5:=6553710
6:=655373
7:=0
Fanuc closed success



Записал лог Wireshark
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
0000   48 2a e3 83 a9 72 2c 4f 52 ea 6a 1b 08 00 45 00
0010   00 6c e5 93 00 00 3c 06 30 2a 0a 75 12 1d 0a 75
0020   41 c8 af c9 ec 1f 31 a1 11 37 5a e3 59 10 50 18
0030   21 b4 ad 19 00 00 a0 a0 a0 a0 00 02 21 02 00 3a
0040   00 01 00 38 00 01 00 01 00 30 00 00 00 00 00 00
0050   00 28 00 00 01 34 00 08 00 00 00 00 00 48 30 30  //308 и 8 получаемые вижу, всё последующее нет.
0060   30 38 20 38 00 00 00 00 00 00 00 00 00 00 00 00
0070   00 00 00 00 00 00 00 00 00 00



Подскажите, пожалуйста, что я упускаю при работе с данной Си++ функцией? Может надо как-то по иному вызывать её? Или дельфи некорректно обрабатывает её ответ?

Спасибо!

ЗЫ. Код писал только для теста получения данных
...
Рейтинг: 0 / 0
13.01.2021, 22:47
    #40035593
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
Вот это
Kast2K
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
typedef struct  odbdgn {
   short datano;              /* diagnosis data number */
   short type;                /* upper byte:type */
                              /* lower byte:axis */
   union {
      char  cdata;            /* bit/byte diagnosis data */
      short idata;            /* word diagnosis data */
      long  ldata;            /* 2-word diagnosis data */
      char  cdatas[MAX_AXIS]; /* bit/byte diagnosis data with axis*/
      short idatas[MAX_AXIS]; /* word diagnosis data with axis */
      long  ldatas[MAX_AXIS]; /* 2-word diagnosis data with axis */
   } u ;
} ODBDGN 

записывается так
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
odbdgn = record
  datano: SmallInt;
  type_: SmallInt;
  case Byte of
    0: (cdata: ShortInt);
    1: (idata: SmallInt);
    2: (ldata: Integer);
    3: (cdatas: array[0..MAX_AXIS - 1] of ShortInt);
    4: (idatas: array[0..MAX_AXIS - 1] of SmallInt);
    5: (ldatas: array[0..MAX_AXIS - 1] of Integer);
end;

Функцию можно объявить так
Код: pascal
1.
function cnc_diagnoss (FlibHndl:Word; number: SmallInt; axis: SmallInt; length: SmallInt; var diag: odbdgn):SmallInt; stdcall; external 'Fwlib32.dll';


Kast2K
Код: pascal
1.
//308 и 8 получаемые вижу, всё последующее нет.

Тут вам нужно смотреть документацию на функцию и что и когда она возвращает
...
Рейтинг: 0 / 0
14.01.2021, 05:30
    #40035646
asutp2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
_Vasilisk_,

odbdgn = record надо объявлять как odbdgn = packed record, иначе делфовский компилятор выравняет поля в завиисмости от {$ALIGN XX}
...
Рейтинг: 0 / 0
14.01.2021, 07:44
    #40035651
Kast2K
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
Коллеги,
спасибо за подсказки!

Но, как оказалось, я сам лопух :) не дочитал спецификацию на дополнительные вычисляемые параметры оборудования и передавал не тот параметр.

Всё работает отлично.
...
Рейтинг: 0 / 0
14.01.2021, 10:34
    #40035675
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
asutp2
dbdgn = record надо объявлять как odbdgn = packed record,
Не надо. И даже вредно.
...
Рейтинг: 0 / 0
14.01.2021, 10:41
    #40035677
Fr0sT-Brutal
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
_Vasilisk_
asutp2
dbdgn = record надо объявлять как odbdgn = packed record,
Не надо. И даже вредно.

Обоснуй?
...
Рейтинг: 0 / 0
14.01.2021, 11:34
    #40035704
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
Fr0sT-Brutal
Обоснуй?

С++ вроде по-умолчанию использует выравнивание то ли 4 то ли 8 байт, как и Delphi.
Это в WinApi всё packed.
...
Рейтинг: 0 / 0
14.01.2021, 12:22
    #40035732
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
alekcvp
Это в WinApi всё packed.
Ничего подобного. В WinApi структуры упакованы сами по себе. Там все поля либо четырехбайтовые, либо появляются всякие reserved.

Пример
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
typedef WORD SECURITY_DESCRIPTOR_CONTROL, *PSECURITY_DESCRIPTOR_CONTROL;

typedef struct _SECURITY_DESCRIPTOR {
  BYTE                        Revision;
  BYTE                        Sbz1;
  SECURITY_DESCRIPTOR_CONTROL Control;
  PSID                        Owner;
  PSID                        Group;
  PACL                        Sacl;
  PACL                        Dacl;
} SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;

Смотри на первые три поля. В сумме 4 байта и все само пакуется
...
Рейтинг: 0 / 0
14.01.2021, 13:29
    #40035777
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
Fr0sT-BrutalОбоснуй?

Ты не поверишь, но Си тоже выравнивает поля. Причём чаще всего точно так же как Дельфи.

Но иногда некоторые указывают Дельфи неверное выравнивание. Поэтому при портировании и непонятках со структурами, первое, что надо сделать, это вывести общую длину структуры и смещение каждого поля в Си и Дельфи. Потом сравнить.
...
Рейтинг: 0 / 0
14.01.2021, 13:42
    #40035786
asutp2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
_Vasilisk_
alekcvp
Это в WinApi всё packed.
Ничего подобного. В WinApi структуры упакованы сами по себе. Там все поля либо четырехбайтовые, либо появляются всякие reserved
Не всегда) Пример - работа с RAS.
Для работы со структурой rassconn требуется {$ALIGN 4}, для всех остальных структур {$ALIGN 8}, a reserved в структурах практически нет вообще
...
Рейтинг: 0 / 0
14.01.2021, 14:12
    #40035807
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
asutp2
Для работы со структурой rassconn требуется {$ALIGN 4},
Она и так сама выровняется на 4 байта, если ей не помешать
asutp2
для всех остальных структур {$ALIGN 8},
Ссылку в студию
...
Рейтинг: 0 / 0
14.01.2021, 14:20
    #40035816
Barmaley57
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
...
Рейтинг: 0 / 0
14.01.2021, 15:00
    #40035839
asutp2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
_Vasilisk_
asutp2
Для работы со структурой rassconn требуется {$ALIGN 4},
Она и так сама выровняется на 4 байта, если ей не помешать
что значит "сама"? вообще то выравнивание как раз регулируется директивой ALIGN. Лично у меня в проектах для виндов по умолчанию именно $ALIGN 8, а не 4, для macos - $ALIGN 16
_Vasilisk_
asutp2
для всех остальных структур {$ALIGN 8},
Ссылку в студию
что, всё плохо с доступом к описанию API в MSDN?
...
Рейтинг: 0 / 0
14.01.2021, 15:11
    #40035843
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
asutp2Лично у меня в проектах для виндов по умолчанию именно $ALIGN 8, а не 4, для macos - $ALIGN 16

Именно это я и имел ввиду когда говорил про чудаков, ставящих левые настройки куда не надо.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
14.01.2021, 15:51
    #40035859
asutp2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
Dimitry Sibiryakov

asutp2Лично у меня в проектах для виндов по умолчанию именно $ALIGN 8, а не 4, для macos - $ALIGN 16

Именно это я и имел ввиду когда говорил про чудаков, ставящих левые настройки куда не надо.
Учитывая, что используемые мною значения как раз и рекомендуются Эмбаркадерой (внимательно смотрим ссылку ), то чудик тут тот, кто не следует обоснованным рекомендациям
...
Рейтинг: 0 / 0
14.01.2021, 15:59
    #40035860
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
Вот только нет по ссылке такой рекомендации.

"For OS X applications, stack alignment must be on 16-byte boundaries."

Внезапно, но "stack alignment" не имеет никакого отношения к "field alignment" и второе не
влияет на первое.

Впрочем, что взять с вики...
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
14.01.2021, 16:29
    #40035871
asutp2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
Dimitry Sibiryakov,

речь идет именно о field alignment, слово stack это всего лишь описка. Поищи в web-архиве эту статью из блога, там было всё подробно расписано
...
Рейтинг: 0 / 0
14.01.2021, 16:40
    #40035872
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
http://web.archive.org/web/20090523104516/https://blogs.embarcadero.com/eboling/2009/05/20/5607
In the Mac OS X ABI Function Call Guide there is an innocent little sentence: "The stack
is 16-byte aligned at the point of function calls."

Перевести или сам как-нибудь справишься?..
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
14.01.2021, 16:48
    #40035876
Kazantsev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
asutp2
речь идет именно о field alignment, слово stack это всего лишь описка.

Дефолтное выравнивание полей записи: dccosx - 8, dccosx64 - 16.
...
Рейтинг: 0 / 0
14.01.2021, 17:35
    #40035894
asutp2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
Kazantsev Alexey,

так сейчас актуально только dccosx64, а 32и битные уже всё, в истории
...
Рейтинг: 0 / 0
14.01.2021, 17:35
    #40035895
asutp2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
Dimitry Sibiryakov

http://web.archive.org/web/20090523104516/https://blogs.embarcadero.com/eboling/2009/05/20/5607
In the Mac OS X ABI Function Call Guide there is an innocent little sentence: "The stack
is 16-byte aligned at the point of function calls."

Перевести или сам как-нибудь справишься?..
Давай жги)
...
Рейтинг: 0 / 0
14.01.2021, 17:51
    #40035899
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
asutp2Давай жги)

"Значение указателя стэк при вызове функции должно быть кратно 16 байт."

Я не знаю какой кретин сумел это хоть как-то связать с выравниванием полей записи, но
надеюсь, что он всё ещё работает в Эмбаркадеро и не может навредить остальному миру.
...
Рейтинг: 0 / 0
14.01.2021, 17:53
    #40035900
Fr0sT-Brutal
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
Ну вот, собственно, о чем я и говорил. Интерфейсные форматы оставлять на откуп платформе и компилятору - плохой путь, ничем не лучше DateToStr(Now).
Вот описали кучу сишных структур без всякой привязки, рассчитывая на выравнивание по 4, а потом в конечном софте вдруг кто-то вхрненачил прагму на 8, а тупорылая сишная манера "сначала засунем все инклюды в один огромный исходник, а его будем компилировать" запросто позволит этой прагме повлиять на ВСЁ, что идет и подключается за ней.
...
Рейтинг: 0 / 0
14.01.2021, 19:45
    #40035936
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
_Vasilisk_
Смотри на первые три поля. В сумме 4 байта и все само пакуется

А ты вообще понимаешь что такое выравнивание?
Если ты эту структуру в Delphi опишешь, то у тебя будет так:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
type
_SECURITY_DESCRIPTOR = record
    Revision: Byte;
    { Padding: array [0..6] of Byte; }
    Sbz1: Byte
    { Padding: array [0..6] of Byte; }
    ....
  end;

То что закомментировано добавит компилятор.
...
Рейтинг: 0 / 0
14.01.2021, 20:13
    #40035943
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Не получить корректный Record по указателю из С++ DLL
alekcvpЕсли ты эту структуру в Delphi опишешь, то у тебя будет так:

Нет, так будет только у asutp2 и ему подобных, которые употребляют опции выравнивания где
не надо.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Не получить корректный Record по указателю из С++ DLL / 25 сообщений из 47, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]