51 (изменено: Malcev, 2018-12-30 02:53:57)

Re: AHK: DllCall и правильный вызов функций.

Что-то я не понял ответа с оф.форума.

In c (cdecl), as far as I know, passing a struct by value is done by copying it on to the stack, including padding. Your only option to put something on the stack, is by passing parameters via dllcall. I'd expect stdcall behaves the same.
For x64 calling convention, refer to MSDN,
https://docs.microsoft.com/en-us/cpp/bu … ew=vs-2017
   

Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed as if they were integers of the same size. Structs or unions of other sizes are passed as a pointer to memory allocated by the caller.

So indeed, struct S {int;int;} must be passed as int64 for x64 calling convention, and it can be for cdecl too. But struct S2 {char c;short s;} would need to be passed as "ptr", &S2 for x64. But, for cdecl, S2 would be passed as "int", c | (s << 16), you cannot do "char", c, "short", s. Finally struct d {double; double; ... double;} must be passed as "ptr", &d for x64 and "double", d1, ..., "double", dn for cdecl.
https://www.autohotkey.com/boards/viewt … 59#p255359

Почему для такой структуры {char c;short s;} нельзя передать так - "char", c, "short", s , а {double; double; double;} можно "double", d1, ..., "double", dn for cdecl?
Еще написали, что при такой передачи width и height могут смешаться:

msgbox % DllCall("opencv_core2413.dll\cvCreateImage", "int", width, "int", height, "int", IPL_DEPTH_8U := 8, "int", channels := 2, "Cdecl Ptr")

Действительно могут?

52

Re: AHK: DllCall и правильный вызов функций.

Malcev пишет:

Еще написали, что при такой передачи width и height могут смешаться:

Нет, он имел в виду порядок width и height. Но они так и должны быть. Правила передачи структур, о которых тут говорится, — это рекомендации для разработчиков. Мы имеем дело с уже готовыми функциями и должны передавать так, как они этого ожидают.

В x64 есть особенности, которые нужно учитывать. Элементы структуры выравниваются по "границе типа". Каждый элемент должен располагаться либо в начале структуры, либо по смещению от начала структуры, кратному его размеру. Если имеем структуру {char, short}, то второй элемент не может быть впритык к первому, т.к. имеет размер 2 байта и, значит, должен быть, как минимум, на смещении 2. Т.е. после char делается отступ в 1 байт, чтобы выравнять short.

Кроме того, размер структуры должен быть кратным самому большому её элементу. В структуре {short, char} к концу нужно добавить 1 байт, чтобы размер был не 3, а 4 байта, кратно short.

Адрес структуры в памяти должен быть тоже кратен размеру самого большого элемента. Но это больше рекомендация, я так понимаю. Если внутри структура выравнена, то проблем быть не должно. Хотя смутно помню какие-то ситуации, где выравнивание данных именно в памяти было критично. Так что если какие-то непонятные глюки, то можно проверить и это условие.

Malcev пишет:

Почему для такой структуры {char c;short s;} нельзя передать так - "char", c, "short", s , а {double; double; double;} можно "double", d1, ..., "double", dn for cdecl?

Потому что char и short меньше, чем ячейка стека (32 бита), а выделено каждому будет по ячейке, как я уже выше писал. Т.е. в итоге в памяти получится char, потом 3 пустых байта, потом short, тогда как short должен лежать сразу же за char (в x86 выравнивание не нужно).

Double занимает ровно 2 ячейки, так что все Double'ы будут идти встык друг за другом, как и должно быть.

53

Re: AHK: DllCall и правильный вызов функций.

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

54

Re: AHK: DllCall и правильный вызов функций.

Лень, наверно.

55

Re: AHK: DllCall и правильный вызов функций.

В AHK_H есть, а в AHK есть библиотека.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

56 (изменено: Malcev, 2018-12-30 19:43:32)

Re: AHK: DllCall и правильный вызов функций.

А можешь привести пример использования библиотеки для отсылки копии структуры для 32bit struct S2 {char c1;short s;char c2;}?
Разве она не ссылки создает?

Struct alows easy access to the world of structures. Simple to use using object syntax, dynamic structure resolution, pointers support and more.It's now so simple to use structures in AHK like never before.

Struct[""] contains pointer of structure so you can pass it to DllCall and SendMessage functions.

https://autohotkey.com/board/topic/5515 … 412-ahkv2/

57

Re: AHK: DllCall и правильный вызов функций.

Я, честно говоря, ни разу не пользовался, люблю сам считать. Попозже могу посмотреть.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

58 (изменено: Malcev, 2018-12-30 20:07:58)

Re: AHK: DllCall и правильный вызов функций.

Еще интересен момент.

But struct S2 {char c;short s;} would need to be passed as "ptr", &S2 for x64

А если функция ожидает копию структуры?
Или она не может ожидать копию структуры на x64 по спефицикации?

Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed as if they were integers of the same size. Structs or unions of other sizes are passed as a pointer to memory allocated by the caller.

59

Re: AHK: DllCall и правильный вызов функций.

Так она и будет размером 32 бита, если с выравниванием.

60

Re: AHK: DllCall и правильный вызов функций.

А разве если мы делаем такую операцию "int", c | (s << 16), мы не получаем, что 1 байт занимает char, потом идет пустой байт, а потом 2 байта short?

61

Re: AHK: DllCall и правильный вызов функций.

Ну да, так и должно быть в x64. В x86 надо сдвинуть на 8.

62

Re: AHK: DllCall и правильный вызов функций.

Тогда отвечающий с оффорума ошибся, когда написал, что для cdecl  нужно сдвигать на 16? А вы не могли бы привести пример, как добавить байт в конец, numput здесь же не поможет? И как создать адрес структуры памяти, кратный самому большому элементу?

63 (изменено: YMP, 2018-12-31 17:32:41)

Re: AHK: DllCall и правильный вызов функций.

А зачем байт добавлять? Если вы в трёхлитровую банку нальёте два литра, то надо ли добавлять третий пустой литр? Так же если вы трёхбайтную структуру передаёте как int, то и четвёртый байт там само собой будет. Функция же знает, что она получает и какую часть объёма int занимает полезная информация. Главное чтобы она лежала правильно. Для x64 с выравниванием, для x86 без выравнивания.

Если создаёте структуру, то опять же просто выделяете 4 байта памяти и располагаете char и short в правильных местах этого объёма.

Адрес проще всего подгонять под кратный восьми. Судя по моим экспериментам, VarSetCapacity на x64 и так всегда выдаёт адреса, кратные 8. На x86 вижу либо то же, либо иногда бывают кратные 4.

Если нужна стопроцентная гарантия, то запрашивайте буфер на 7 байт больше, чем нужно, потом к адресу переменной прибавляйте 7 и округляйте результат до 8. Этот адрес уже и используйте для структуры.


VarSetCapacity(v1, sruct_size + 7)
pStruct := ((&v1 + 7) >> 3) << 3

Сдвиг на 3 бита вправо равносилен целочисленному делению на 8 (с отбрасыванием остатка), влево — умножению на 8. На 3 потому, что 8 — это третья степень двойки, а биты же двоичные числа.

В cdecl аргументы в стеке размещаются точно так же, как в stdcall. Разница между ними в том, кто их потом оттуда убирает. В cdecl это делает вызвавший функцию код, а в stdcall сама эта функция.

64

Re: AHK: DllCall и правильный вызов функций.

У меня получается адрес памяти всегда кратным A_PtrSize, при том для 32bit всегда некратным 8.
То есть адрес и так всегда будет кратен самому большому элементу в структуре для 64 бит, а для 32 бит, как вы сказали, это необязательно.
А почему вы прибавляете именно 7?
И почему если мы раскомментируем msgbox то результат будет другим?

sruct_size := 16
VarSetCapacity(v1, sruct_size + 7)
; msgbox % &v1
pStruct := ((&v1 + 7) >> 3) << 3
msgbox % &v1 "`n" pStruct

И создание адреса структуры кратного самому большому элементу необходимо только при посылании структуры как ссылки?
И например такую структуру

struct ST1 {
    char c1;   1
    short s1;   2
    word w; 2
    double d;   8
};

для 32 бит нужно передавать так?

"int64", c1 | (s1 << 8) | (w << 24), "double" d

А для 64 так?

"int64", c1 | (s1 << 16) | (w << 32), "double" d

65

Re: AHK: DllCall и правильный вызов функций.

Malcev пишет:

И почему если мы раскомментируем msgbox то результат будет другим?

Не знаю, а почему это важно?

Malcev пишет:

И создание адреса структуры кратного самому большому элементу необходимо только при посылании структуры как ссылки?

Видимо. В отношении стека я об этом не слышал. Ячейки его и так выровнены.

Malcev пишет:

И например такую структуру для 32 бит нужно передавать так?

А это реальный случай? Что-то я сомневаюсь. Как её передал бы компилятор С, я не знаю. В принципе, наверно, мог бы как угодно, поскольку ведь код той функции, которая эту структуру принимает и использует, тоже он пишет. Он может просто выделить достаточное место в стеке и записать её туда либо ближе к началу этого места, либо ближе к концу, либо посередине. Нам нет смысла гадать.

66

Re: AHK: DllCall и правильный вызов функций.

YMP пишет:

а почему это важно?

Просто интересно такое поведение.

YMP пишет:

А это реальный случай?

Не, выдуманный.
Так всё-таки почему вы именно на 7 байт больше запрашивали буфер?
Кстати, на оффоруме функцию написали, правда для ahk2:
https://github.com/HelgeffegleH/AHK-mis … all_struct

67

Re: AHK: DllCall и правильный вызов функций.

Malcev пишет:

Просто интересно такое поведение.

Ну, видимо, MsgBox тоже использует память.

Malcev пишет:

Так всё-таки почему вы именно на 7 байт больше запрашивали буфер?

Это максимум, на который может сдвинуться вперёд адрес при округлении. Ведь расстояние между круглыми адресами 8 байт.

Malcev пишет:

Кстати, на оффоруме функцию написали, правда для ahk2

При том, что тема была про v1.

68

Re: AHK: DllCall и правильный вызов функций.

На оффоруме автор функции написал, что и в x32 и в x64 элементы структуры нужно выравнивать по границе типа.
Структура {char c;short s;} передается всегда как "int", c | (s << 16).
В википедии вроде также написано:

struct MixedData
{
    char Data1;
    short Data2;
    int Data3;
    char Data4;
};

After compilation the data structure will be supplemented with padding bytes to ensure a proper alignment for each of its members:

struct MixedData  /* After compilation in 32-bit x86 machine */
{
    char Data1; /* 1 byte */
    char Padding1[1]; /* 1 byte for the following 'short' to be aligned on a 2 byte boundary
assuming that the address where structure begins is an even number */
    short Data2; /* 2 bytes */
    int Data3;  /* 4 bytes - largest structure member */
    char Data4; /* 1 byte */
    char Padding2[3]; /* 3 bytes to make total size of the structure 12 bytes */
};

https://en.wikipedia.org/wiki/Data_structure_alignment

69

Re: AHK: DllCall и правильный вызов функций.

Если структура передаётся по ссылке 32-битной WinAPI функции, то не нужно. По крайней мере я никогда этого не делал, и никаких проблем не было. А как там компиляторы внутри программ эти структуры передают, это нас не касается. Для нас важен внешний интерфейс, с которым мы только и имеем дело. А тут требование выравнивания есть только для x64.

Конечно, можно предположить, что все структуры для x86 WinAPI так организованы, что и выравнивать не надо. Ну, может быть. Я каждую специально на этот предмет не проверял. Но это только гипотеза. Надо смотреть конкретные примеры структур.

70

Re: AHK: DllCall и правильный вызов функций.

А у вас есть ссылка на документацию, где написаны эти требования для передачи структур для x64 и для x86?
И если передавать x86 с выравниванием по границе типа, то будет ошибка?

71

Re: AHK: DllCall и правильный вызов функций.

Нет, ссылки нету.

Сейчас проверил вот эту структуру в Visual C++.


typedef struct tagRAWMOUSE {
    USHORT usFlags;
    union {
        ULONG ulButtons;
        struct  {
            USHORT  usButtonFlags;
            USHORT  usButtonData;
        };
    };
    ULONG ulRawButtons;
    LONG lLastX;
    LONG lLastY;
    ULONG ulExtraInformation;
} RAWMOUSE, *PRAWMOUSE, *LPRAWMOUSE;

Расстояние от начала структуры до ulButtons показывает 4 байта. Значит, выравнивание всё-таки есть и в x86. Видимо, верна моя догадка, что большинство структур так составлено, что выравнивание не требуется, поэтому и нет ошибок, даже если про него не думаешь.

72

Re: AHK: DllCall и правильный вызов функций.

Malcev пишет:

такую структуру

struct ST1 {
    char c1;   1
    short s1;   2
    word w; 2
    double d;   8
};

для 32 бит нужно передавать так?

"int64", c1 | (s1 << 8) | (w << 24), "double" d

А для 64 так?

"int64", c1 | (s1 << 16) | (w << 32), "double" d

Для 64 бит нужно передавать ссылкой, так как размер ее не равен 8, 16, 32, or 64 bits.

73

Re: AHK: DllCall и правильный вызов функций.

В общем, это логично. Первые 4 аргумента в x64 передаются в регистрах процессора. Если структура занимает 48 бит, вы не можете её из регистра записать в память как 48 бит, по кр. мере не за одну инструкцию процессора. За одну придётся писать сразу 64 бита. А если структура, к примеру, расположена в самом конце буфера памяти, то вы выйдете на 16 бит за его конец и перезапишете там какие-то другие данные нулями. Если же она находится в конце страницы памяти, а следующая страница не была выделена, то, наверно, будет исключение доступа. Тут даже и попытка чтения, по идее, может его вызвать.

8, 16 и 32 бита разрешены, поскольку эти части 64-битного регистра можно использовать, как самостоятельные регистры. Например, в регистре RAX можно к ним обращаться, как AL, AX и EAX. Так что здесь вы лишнего писать не будете.

74 (изменено: Malcev, 2019-01-21 14:11:42)

Re: AHK: DllCall и правильный вызов функций.

А возможно ли вызвать методы класса из dll?

§ imread()
Mat cv::imread 	( 	const String &  	filename,
		int  	flags = IMREAD_COLOR 
	) 		
Python:
	retval	=	cv.imread(	filename[, flags]	)

https://docs.opencv.org/3.4.5/d4/da8/gr … 7b3bbd3a56
Dll Export Viewer показывает:

class cv::Mat __cdecl cv::imread(class cv::String const & __ptr64,int)

Через NET Framework Interop (CLR, C#, VB) вообще dll не загружается - выводит ошибку.
https://www.autohotkey.com/boards/viewtopic.php?t=4633