Здравствуйте, MasterZiv, Вы писали:
MZ>Как угодно, в зависимости от желания. В рантайме конечно MZ>скорее всего трудновато будет создавать сами функции (компилятор MZ>там вызывать и прочее), но вот их описания -- кто ж запрещает ?
Там нет переменного количества параметров, это я ошибся, но желательно создавать сами функции, причем без вызова компилятора. На .Net это легко — делегат можно инициализировать как статической функцией, так и нестатической функцией класса. В общем, спасибо за ответы.
Re[3]: Вызов dll функций с переменным числом параметров
Здравствуйте, dandy, Вы писали:
D>Как сделать в плагине не статический массив указателей на функции, а динамический массив указателей на функции: that is the question
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Вызов dll функций с переменным числом параметров
Здравствуйте, MasterZiv, Вы писали:
MZ>Да. Только у тебя функция неправильно оформлена -- как минимум один параметр у MZ>неё должен быть. во-первых, от него и будут отсчитываться остальные параметры, MZ>во-вторых, ты должен на основании значения этого параметра понять, сколько MZ>у тебя всего других параметров.
Не должно.
Если, к примеру, используется не передача количества в 1-м параметре, что чревато ошибками, а используется замыкающий параметр.
Типа того:
my_func("1", "2", "3", NULL);
Re[4]: Вызов dll функций с переменным числом параметров
Здравствуйте, Аноним, Вы писали:
А>Есть приложение, которое грузит плагины. При инициализации плагина оно вызывает из него функцию, посредством которой оно заполняет массив структур с описаниями экспортируемыми из плагина функциями. В структуре есть указатель на экспортируемую функцию и информация о количестве/типе ее параметров. Мне нужно создавать этот массив динамически, чтобы можно было использовать в dll любое количество функций с любым количеством параметров. Вопрос — как это сделать. Пока единственная идея — использовать в dll/плагине экспортируемые функции с переменным числом аргументов, например так:
Очень похоже на изобретение велосипеда, помноженное на кривую архитектуру.
Подобная задача уже решена, например, в COM — IDispatch сотоварищи.
Опять же, если это плагин, значит, его интерфейс уже известен. Приложение ожидает от плагина какие-то конкретные функции с какими-то конкретными сигнатурами. Может быть, не все эти функции реализованы...
В таком случае есть тупой, но рабочий подход! Пусть плагин экспортирует функции, как обычная dll (только без декорирования имён) — extern "C" __declspec(dllexport).
Приложение грузит эти функции через GetProcAddress, и если чего-то не находит, то и чёрт с ним.
А если плагин отдаёт библиотеку произвольных функций, которые приложение использует в каких-то скриптах... Тогда стоит сразу же определиться, что это за скрипты, и какой для данного скриптового движка естественный биндинг. И пусть плагин отдаёт информацию сразу готовую для движка.
Перекуём баги на фичи!
Re[2]: Вызов dll функций с переменным числом параметров
Здравствуйте, Кодт, Вы писали:
К>А если плагин отдаёт библиотеку произвольных функций, которые приложение использует в каких-то скриптах... Тогда стоит сразу же определиться, что это за скрипты, и какой для данного скриптового движка естественный биндинг. И пусть плагин отдаёт информацию сразу готовую для движка.
Тут уже где — то было написано, что приложение невозможно переделать. Этот плагин должен работать как переходник между кривым плагинным интерфейсом проги и .Net плагинами и должен предоставлять удобный .Net API для них. Вопрос в том, как красивее связать библиотеки функций .Net плагинов, число которых заранее неизвестно, с библиотекой функций, которую плагин — переходник должен передавать в прогу.
Re[6]: Вызов dll функций с переменным числом параметров
Здравствуйте, MasterZiv, Вы писали:
MZ>Как угодно, в зависимости от желания. В рантайме конечно MZ>скорее всего трудновато будет создавать сами функции (компилятор MZ>там вызывать и прочее), но вот их описания -- кто ж запрещает ?
D>Тут уже где — то было написано, что приложение невозможно переделать. Этот плагин должен работать как переходник между кривым плагинным интерфейсом проги и .Net плагинами и должен предоставлять удобный .Net API для них. Вопрос в том, как красивее связать библиотеки функций .Net плагинов, число которых заранее неизвестно, с библиотекой функций, которую плагин — переходник должен передавать в прогу.
Ну заверни дотнетного делегата в ком-объект, и отдавай наружу фабрику таких объектов...
Только, наверное, прийдётся аутпроц сервер делать, чтобы дотнет жилю
Или захачь интероп, как тебе Кодт советовал, а из плагина всё равно фабрику ком-объектов отдавай...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Вызов dll функций с переменным числом параметров
Здравствуйте, Erop, Вы писали:
E>Ну заверни дотнетного делегата в ком-объект, и отдавай наружу фабрику таких объектов... E>Только, наверное, прийдётся аутпроц сервер делать, чтобы дотнет жилю E>Или захачь интероп, как тебе Кодт советовал, а из плагина всё равно фабрику ком-объектов отдавай...
Возможно интероп подойдет. Все, пошел спать!!!!!!!
Re[5]: Вызов dll функций с переменным числом параметров
D>Возможно интероп подойдет. Все, пошел спать!!!!!!!
А зачем тебе, чтобы управляемый код жил в ространстве нативного приложения?
Ради производительности? Они же мешать друг другу могут.
Как часто вызовы-то будут проходить?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Вызов dll функций с переменным числом параметров
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Аноним, Вы писали:
А>>Вопрос — как это сделать. E>Ну, например, можно возвращать указатель на статический массив и счётчик.
так эти три точки ... которые va_list и реализованы как массив указателей на аргументы c нулевым поинтером в конце
Re[6]: Вызов dll функций с переменным числом параметров
Здравствуйте, Erop, Вы писали:
E>А зачем тебе, чтобы управляемый код жил в ространстве нативного приложения? E>Ради производительности? Они же мешать друг другу могут. E>Как часто вызовы-то будут проходить?
Прости за оффтоп, но ты когда — нибудь спишь?
Re[7]: Вызов dll функций с переменным числом параметров
D>Прости за оффтоп, но ты когда — нибудь спишь?
Раз в несколько дней
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[8]: Вызов dll функций с переменным числом параметров
D>Посмотрел код, в vc 2008 это сделано уже и для x64 и пр. Только там __stdcall, мне нужно __cdecl. D>Файл <atlstdthunk.h>
Очень трудно понять, что же тебе надо.
Я так понял, что у тебя есть какое-то нативное приложение, у которого есть интерфейс к своим плагинам.
И ты хочешь предоставить возможность динамически плодить плагины на дотнете.
В твоём понимании дотнетовская функция для плагина -- это делегат.
Это то, что я понял, не факт, что правильно.
Чего я не понял, так это того, входит ли в описание функции для плагина указатель на данные? То есть можно ли конкретный делегат идентифицировать по указатею на данные, а не на код?
Собственно задача распадается на три куска.
1) Как в пространстве материнского приложения запустить дотнет? Мой ответ: не надо так делать. Дотнет тяжёлая прожорливая хрень. Она можжет нагнуть приложение, могут повылазить невыявленные при стресс-тестировании приложения баги, и стабильно это может так и не заработать. Намного надёжнее запускать дотнет в другом процессе, а интероп сделать через межпроцессный вызов, например через RPC, но под виндой прямее ком, КМК.
2) Как организовать вызов из нативного кода плагинной DLL дотнетовского делегата. Ясно, что в С++ части будет какой-то объект, который будет иметь внутри указатель на делегат, и дёргать его. Но если в (1) заюзать ком, то этот кусок выраждается до банального COMPtr
3) Как продать объекты из (2) приложению, под видом функций. Собственно, если интерфейс приложения к плагинам позволяет идентиицировать конкретную функцию указателем на данные, а не на код, то нет проблем. В качестве указателя на функцию отдаёшь функцию, которая ждёт указатель на данные, досттаёт из него нужный ком-интерфейс и зовёт функцию, дёргающую, в конце концов делегата.
Но я так понял, что интерфейс приложения к плагинам подраазумевает, что функцию определяет именно указатель на код, а указатель на данные использовать нельзя.
Тогда есть два варианта.
Вариат 1.
Пул функций.
Тут либо шаблоны, либо макросы, либо генератор (или ручки вместо генератора)
Вариант 2
Генерённый код.
Тут тоже не сложно.
Типа пишем шаблон кода, который делает
push [подставить ID конкретной функции]
jp [функция на С++, которая ID получит как аргумент и разрулит...]
Заводим память, в которую можн писать и которую можно исполнять и плодим эти thunk-функции в том количестве, в котором нам надо...
Я вообще верно понял твою задачу?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: Вызов dll функций с переменным числом параметров
E>Очень трудно понять, что же тебе надо. E>Я так понял, что у тебя есть какое-то нативное приложение, у которого есть интерфейс к своим плагинам. E>И ты хочешь предоставить возможность динамически плодить плагины на дотнете.
Нужно динамически загружать все плагины, у которые используют дотнетовские классы моего плагина.
E>В твоём понимании дотнетовская функция для плагина -- это делегат. E>Это то, что я понял, не факт, что правильно.
Не так, но это неважно.
E>Чего я не понял, так это того, входит ли в описание функции для плагина указатель на данные? То есть можно ли конкретный делегат идентифицировать по указатею на данные, а не на код?
Да входит. Но идентифицировать нужно по указателю на функцию.
E>Собственно задача распадается на три куска. E>1) Как в пространстве материнского приложения запустить дотнет? Мой ответ: не надо так делать. Дотнет тяжёлая прожорливая хрень. Она можжет нагнуть приложение, могут повылазить невыявленные при стресс-тестировании приложения баги, и стабильно это может так и не заработать. Намного надёжнее запускать дотнет в другом процессе, а интероп сделать через межпроцессный вызов, например через RPC, но под виндой прямее ком, КМК.
Все должно быть в одном процессе.
E>2) Как организовать вызов из нативного кода плагинной DLL дотнетовского делегата. Ясно, что в С++ части будет какой-то объект, который будет иметь внутри указатель на делегат, и дёргать его. Но если в (1) заюзать ком, то этот кусок выраждается до банального COMPtr
E>3) Как продать объекты из (2) приложению, под видом функций. Собственно, если интерфейс приложения к плагинам позволяет идентиицировать конкретную функцию указателем на данные, а не на код, то нет проблем. В качестве указателя на функцию отдаёшь функцию, которая ждёт указатель на данные, досттаёт из него нужный ком-интерфейс и зовёт функцию, дёргающую, в конце концов делегата.
Там через делегаты IMHO будет сложно для пользователей. Это я еще не смотрел, но IMHO проще будет через рефлексию и производные классы. COM не пойдет по той же причине.
E>Но я так понял, что интерфейс приложения к плагинам подраазумевает, что функцию определяет именно указатель на код, а указатель на данные использовать нельзя.
Да
E>Тогда есть два варианта. E>Вариат 1. E>Пул функций.
E>Тут либо шаблоны, либо макросы, либо генератор (или ручки вместо генератора)
Просто, но некрасиво, писал уже об этом.
E>Вариант 2 E>Генерённый код.
E>Тут тоже не сложно. E>Типа пишем шаблон кода, который делает
E>push [подставить ID конкретной функции]
E>jp [функция на С++, которая ID получит как аргумент и разрулит...]
E>Заводим память, в которую можн писать и которую можно исполнять и плодим эти thunk-функции в том количестве, в котором нам надо...
В ассемблере я не силен к сожалению.
Есть еще 3 — й вариант — чистый .NET
E>Я вообще верно понял твою задачу?
Re[8]: Вызов dll функций с переменным числом параметров
Здравствуйте, dandy, Вы писали:
D>Посмотрел код, в vc 2008 это сделано уже и для x64 и пр. Только там __stdcall, мне нужно __cdecl. D>Файл <atlstdthunk.h>
Ну и что, что __stdcall.
Посмотрим на байткод функции такого вида
typedef int __stdcall CALLEE(intptr_t cookie, va_list args);
int __cdecl thunk(...)
{
va_list args;
va_start(args);
returncallee(cookie, args);
}
и напишем свой собственный генератор санок.
Причём можно параметризовать его не двумя значениями (адрес функции callee и произвольный указатель cookie), а одним (cookie — указатель на интерфейс)
struct ICookie
{
virtual int call(va_list args) = 0;
};
int __stdcall callee(ICookie* cookie, va_list args) { return cookie->call(args); }
можно, конечно, напрямую из thunk вызывать виртуальную функцию, но это слишком много байт
Кстати говоря, поскольку __cdecl предполагает очистку стека вызывающей стороной, то концевой вызов можно заменить на прыжок.
thunk proc
; на стеке сейчас: (return-to) (arg1) (arg2) ... (argN)
; ^-- esp ^-- esp+4
pop eax ; (return-to)
push esp ; (&arg1)
pushcookiepush eax ; (return-to)
; теперь на стеке: (return-to) (cookie) (&arg1) (arg1) (arg2) ... (argN)
jmpcallee
; по завершении - перейдём на (return-to) инструкцией ret 8 (очистив два своих аргумента)
; и оставим на стеке (arg1)...(argN)
; а вызывающая сторона почистит стек до argN уже сама
thunk endp
Аналогично делается для x64 и ARM.
(Только, насколько я помню, у арма stdcall такой же, как и fastcall, т.е. два первых аргумента передаются через регистры)
Перекуём баги на фичи!
Re[9]: Вызов dll функций с переменным числом параметров
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, dandy, Вы писали:
D>>Посмотрел код, в vc 2008 это сделано уже и для x64 и пр. Только там __stdcall, мне нужно __cdecl. D>>Файл <atlstdthunk.h>
К>Ну и что, что __stdcall. К>Посмотрим на байткод функции такого вида К>
К>и напишем свой собственный генератор санок.
К>Причём можно параметризовать его не двумя значениями (адрес функции callee и произвольный указатель cookie), а одним (cookie — указатель на интерфейс) К>
К>можно, конечно, напрямую из thunk вызывать виртуальную функцию, но это слишком много байт
К>Кстати говоря, поскольку __cdecl предполагает очистку стека вызывающей стороной, то концевой вызов можно заменить на прыжок. К>
К>thunk proc
К> ; на стеке сейчас: (return-to) (arg1) (arg2) ... (argN)
К> ; ^-- esp ^-- esp+4
К> pop eax ; (return-to)
К> push esp ; (&arg1)
К> pushcookie
К> push eax ; (return-to)
К> ; теперь на стеке: (return-to) (cookie) (&arg1) (arg1) (arg2) ... (argN)
К> jmpcallee
К> ; по завершении - перейдём на (return-to) инструкцией ret 8 (очистив два своих аргумента)
К> ; и оставим на стеке (arg1)...(argN)
К> ; а вызывающая сторона почистит стек до argN уже сама
К>thunk endp
К>
К>Аналогично делается для x64 и ARM. К>(Только, насколько я помню, у арма stdcall такой же, как и fastcall, т.е. два первых аргумента передаются через регистры)
Ассемблер не знаю, увы, так что с этим связываться неохота.
Re[10]: Вызов dll функций с переменным числом параметров
Здравствуйте, dandy, Вы писали:
D>В ассемблере я не силен к сожалению.
Сделай шаблонный или макросный пул функций-редеректоров...
D>Есть еще 3 — й вариант — чистый .NET
Если ты можешь само приложение переписывать, то в чём вообще запара? Сделай удобный интерфейс к плагинам (чтобы функция определлась ПАРОЙ указателей: указателем на код и указатеем на данные, который при вызове передаётся в эту самую указуемую функцию) и не страдай...
E>>Я вообще верно понял твою задачу? D>
Мне так кажется, что если ты понятно расскажешь что делаешь, помочь теюе будет намного легче...
Да, и, кстати, объясни мне, зачем дотнет запускать в своём нативном процессе? Это какую вгоду приносит? Ну и в любом случае ком и так и так умеет. На дотнете ком-объекты пишутся стандартно, есть куча кода, который это поддерживает и облегчает, так что мне лично не понятно, зачем гонять через интерфейс плагина какие-то хреновины, а не комовские интерфейсы...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[11]: Вызов dll функций с переменным числом параметров
D>>Есть еще 3 — й вариант — чистый .NET
E>Если ты можешь само приложение переписывать, то в чём вообще запара? Сделай удобный интерфейс к плагинам (чтобы функция определлась ПАРОЙ указателей: указателем на код и указатеем на данные, который при вызове передаётся в эту самую указуемую функцию) и не страдай...
Не могу я его переписать. Если мог бы, все было бы просто. Грузил бы .NET плагины из C++ managed dll. Мечты...
E>Мне так кажется, что если ты понятно расскажешь что делаешь, помочь теюе будет намного легче...
E>Да, и, кстати, объясни мне, зачем дотнет запускать в своём нативном процессе? Это какую вгоду приносит? Ну и в любом случае ком и так и так умеет. На дотнете ком-объекты пишутся стандартно, есть куча кода, который это поддерживает и облегчает, так что мне лично не понятно, зачем гонять через интерфейс плагина какие-то хреновины, а не комовские интерфейсы...
Нужно через мой плагин обеспечить максимально удобный .NET API для работы с прогой из пользовательских .NET библиотек классов. COM сложен в использовании, можно сделать намного проще для пользователя, поэтому он сразу отпадает.