Жесткая типизация в языке С++ подчас создаёт непреодолимые трудности. Например, вы, программист-разработчик, и занимаетесь реализацией некоего модульного проекта. Предположим, что это звуковой редактор с плагинами. Плагины вы реализуете в виде .dll, которые динамически подключаются при загрузке редактора. И всё бы ничего, но функции плагинов настолько разнообразны и разноплановы, что описать их в некоем формализованном виде просто нереально. В самом деле, представьте: один плагин принимает пять параметров, возвращает три; другой плагин принимает десять входных аргументов, и не выдает ни одного, зато пишет файл и рисует график на экране. Как быть в таком случае?
У вас есть имя функции, которую нужно выполнить, и список параметров (типов), которые нужно передать функции. Достаточно ли этого в условиях жесткой типизации языка С++, чтобы выполнить функцию? Оказывается, вполне достаточно, если воспользоваться прямым помещением параметров в стек с помощью встроенного ассемблера, а по имени функции извлечь ее адрес из .dll с помощью WinAPI-функции ::GetProcAddress(). Другими словами, это позволяет избавиться от объявления функции непосредственно в коде программы, и вынести объявление функции во внешний конфигурационный файл.
Приблизительный код универсального вызывателя функций приведен ниже. Первым идёт параметр-указатель на функцию вида void func(), массив Array содержит значения или указатели любых типов, приведенных к __int32 (то есть двойное слово, DWORD, определено как stack_cell_t), и Count содержит количество двойных слов. Входные данные в Array должны быть выровнены по 4-байтной границе.
В таком виде, как описано выше, функция call() будет возвращать 64-битное целое, которое может преобразовано в целое любого другого типа, либо в любой указатель.
Если необходимо возвратить число с плавающей запятой, то строки
необходимо заменить на
Разумеется, ResultFloat64 нужно объявить в функции call как double.
P.S. Вообще, описанный материал достаточно обширный и предоставляет немалое поле для разного рода исследований и проверок. При необходимости, Куб 0 выложит дополнительную информацию и примеры в комментариях.
У вас есть имя функции, которую нужно выполнить, и список параметров (типов), которые нужно передать функции. Достаточно ли этого в условиях жесткой типизации языка С++, чтобы выполнить функцию? Оказывается, вполне достаточно, если воспользоваться прямым помещением параметров в стек с помощью встроенного ассемблера, а по имени функции извлечь ее адрес из .dll с помощью WinAPI-функции ::GetProcAddress(). Другими словами, это позволяет избавиться от объявления функции непосредственно в коде программы, и вынести объявление функции во внешний конфигурационный файл.
Приблизительный код универсального вызывателя функций приведен ниже. Первым идёт параметр-указатель на функцию вида void func(), массив Array содержит значения или указатели любых типов, приведенных к __int32 (то есть двойное слово, DWORD, определено как stack_cell_t), и Count содержит количество двойных слов. Входные данные в Array должны быть выровнены по 4-байтной границе.
|
В таком виде, как описано выше, функция call() будет возвращать 64-битное целое, которое может преобразовано в целое любого другого типа, либо в любой указатель.
Если необходимо возвратить число с плавающей запятой, то строки
|
необходимо заменить на
|
Разумеется, ResultFloat64 нужно объявить в функции call как double.
P.S. Вообще, описанный материал достаточно обширный и предоставляет немалое поле для разного рода исследований и проверок. При необходимости, Куб 0 выложит дополнительную информацию и примеры в комментариях.