Re[6]: Вызов dll функций с переменным числом параметров
От: dandy  
Дата: 16.11.11 16:02
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Как угодно, в зависимости от желания. В рантайме конечно

MZ>скорее всего трудновато будет создавать сами функции (компилятор
MZ>там вызывать и прочее), но вот их описания -- кто ж запрещает ?

Там нет переменного количества параметров, это я ошибся, но желательно создавать сами функции, причем без вызова компилятора. На .Net это легко — делегат можно инициализировать как статической функцией, так и нестатической функцией класса. В общем, спасибо за ответы.
Re[3]: Вызов dll функций с переменным числом параметров
От: Erop Россия  
Дата: 16.11.11 16:13
Оценка:
Здравствуйте, dandy, Вы писали:

D>Как сделать в плагине не статический массив указателей на функции, а динамический массив указателей на функции: that is the question


А что за проблема?
Ну делаешь типа
typedef SomeVar TFunction(int, SomeStruct *);
std::vector<TFunction*> myArrayOfFunctions;
и вперёд...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Вызов dll функций с переменным числом параметров
От: sts  
Дата: 16.11.11 16:16
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Да. Только у тебя функция неправильно оформлена -- как минимум один параметр у

MZ>неё должен быть. во-первых, от него и будут отсчитываться остальные параметры,
MZ>во-вторых, ты должен на основании значения этого параметра понять, сколько
MZ>у тебя всего других параметров.

Не должно.
Если, к примеру, используется не передача количества в 1-м параметре, что чревато ошибками, а используется замыкающий параметр.
Типа того:
my_func("1", "2", "3", NULL);
Re[4]: Вызов dll функций с переменным числом параметров
От: dandy  
Дата: 16.11.11 17:06
Оценка:
Здравствуйте, Erop, Вы писали:

E>А что за проблема?

E>Ну делаешь типа
typedef SomeVar TFunction(int, SomeStruct *);
E>std::vector<TFunction*> myArrayOfFunctions;
E>
и вперёд...


Да, но чем ты хочешь инициализировать этот вектор? Если ты хочешь написать очень много глобальных функций, то про это есть пост выше по ветке.
Re: Вызов dll функций с переменным числом параметров
От: Кодт Россия  
Дата: 16.11.11 17:46
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Есть приложение, которое грузит плагины. При инициализации плагина оно вызывает из него функцию, посредством которой оно заполняет массив структур с описаниями экспортируемыми из плагина функциями. В структуре есть указатель на экспортируемую функцию и информация о количестве/типе ее параметров. Мне нужно создавать этот массив динамически, чтобы можно было использовать в dll любое количество функций с любым количеством параметров. Вопрос — как это сделать. Пока единственная идея — использовать в dll/плагине экспортируемые функции с переменным числом аргументов, например так:


Очень похоже на изобретение велосипеда, помноженное на кривую архитектуру.

Подобная задача уже решена, например, в COM — IDispatch сотоварищи.

Опять же, если это плагин, значит, его интерфейс уже известен. Приложение ожидает от плагина какие-то конкретные функции с какими-то конкретными сигнатурами. Может быть, не все эти функции реализованы...
В таком случае есть тупой, но рабочий подход! Пусть плагин экспортирует функции, как обычная dll (только без декорирования имён) — extern "C" __declspec(dllexport).
Приложение грузит эти функции через GetProcAddress, и если чего-то не находит, то и чёрт с ним.

А если плагин отдаёт библиотеку произвольных функций, которые приложение использует в каких-то скриптах... Тогда стоит сразу же определиться, что это за скрипты, и какой для данного скриптового движка естественный биндинг. И пусть плагин отдаёт информацию сразу готовую для движка.
Перекуём баги на фичи!
Re[2]: Вызов dll функций с переменным числом параметров
От: dandy  
Дата: 16.11.11 18:46
Оценка:
Здравствуйте, Кодт, Вы писали:

К>А если плагин отдаёт библиотеку произвольных функций, которые приложение использует в каких-то скриптах... Тогда стоит сразу же определиться, что это за скрипты, и какой для данного скриптового движка естественный биндинг. И пусть плагин отдаёт информацию сразу готовую для движка.


Тут уже где — то было написано, что приложение невозможно переделать. Этот плагин должен работать как переходник между кривым плагинным интерфейсом проги и .Net плагинами и должен предоставлять удобный .Net API для них. Вопрос в том, как красивее связать библиотеки функций .Net плагинов, число которых заранее неизвестно, с библиотекой функций, которую плагин — переходник должен передавать в прогу.
Re[6]: Вызов dll функций с переменным числом параметров
От: Кодт Россия  
Дата: 16.11.11 19:47
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Как угодно, в зависимости от желания. В рантайме конечно

MZ>скорее всего трудновато будет создавать сами функции (компилятор
MZ>там вызывать и прочее), но вот их описания -- кто ж запрещает ?

В рантайме, под конкретную платформу (i386/win32) — как нефиг делать.
ATL thunk <atlstdthunk.h>
или вот выжимка
http://rsdn.ru/forum/cpp/452414.1.aspx
Автор: Yess
Дата: 22.11.03

или на codeproject было ещё...
Перекуём баги на фичи!
Re[3]: Вызов dll функций с переменным числом параметров
От: Erop Россия  
Дата: 16.11.11 20:44
Оценка:
Здравствуйте, dandy, Вы писали:


D>Тут уже где — то было написано, что приложение невозможно переделать. Этот плагин должен работать как переходник между кривым плагинным интерфейсом проги и .Net плагинами и должен предоставлять удобный .Net API для них. Вопрос в том, как красивее связать библиотеки функций .Net плагинов, число которых заранее неизвестно, с библиотекой функций, которую плагин — переходник должен передавать в прогу.


Ну заверни дотнетного делегата в ком-объект, и отдавай наружу фабрику таких объектов...
Только, наверное, прийдётся аутпроц сервер делать, чтобы дотнет жилю
Или захачь интероп, как тебе Кодт советовал, а из плагина всё равно фабрику ком-объектов отдавай...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Вызов dll функций с переменным числом параметров
От: dandy  
Дата: 16.11.11 21:03
Оценка:
Здравствуйте, Erop, Вы писали:

E>Ну заверни дотнетного делегата в ком-объект, и отдавай наружу фабрику таких объектов...

E>Только, наверное, прийдётся аутпроц сервер делать, чтобы дотнет жилю
E>Или захачь интероп, как тебе Кодт советовал, а из плагина всё равно фабрику ком-объектов отдавай...

Возможно интероп подойдет. Все, пошел спать!!!!!!!
Re[5]: Вызов dll функций с переменным числом параметров
От: Erop Россия  
Дата: 17.11.11 01:46
Оценка:
Здравствуйте, dandy, Вы писали:


D>Возможно интероп подойдет. Все, пошел спать!!!!!!!


А зачем тебе, чтобы управляемый код жил в ространстве нативного приложения?
Ради производительности? Они же мешать друг другу могут.
Как часто вызовы-то будут проходить?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Вызов dll функций с переменным числом параметров
От: dudkin  
Дата: 17.11.11 02:35
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Аноним, Вы писали:


А>>Вопрос — как это сделать.

E>Ну, например, можно возвращать указатель на статический массив и счётчик.

так эти три точки ... которые va_list и реализованы как массив указателей на аргументы c нулевым поинтером в конце
Re[6]: Вызов dll функций с переменным числом параметров
От: dandy  
Дата: 17.11.11 06:01
Оценка:
Здравствуйте, Erop, Вы писали:

E>А зачем тебе, чтобы управляемый код жил в ространстве нативного приложения?

E>Ради производительности? Они же мешать друг другу могут.
E>Как часто вызовы-то будут проходить?

Прости за оффтоп, но ты когда — нибудь спишь?
Re[7]: Вызов dll функций с переменным числом параметров
От: dandy  
Дата: 17.11.11 07:01
Оценка:
Здравствуйте, Кодт, Вы писали:

К>В рантайме, под конкретную платформу (i386/win32) — как нефиг делать.

К>ATL thunk <atlstdthunk.h>
К>или вот выжимка
К>http://rsdn.ru/forum/cpp/452414.1.aspx
Автор: Yess
Дата: 22.11.03

К>или на codeproject было ещё...

Посмотрел код, в vc 2008 это сделано уже и для x64 и пр. Только там __stdcall, мне нужно __cdecl.
Файл <atlstdthunk.h>
Re[7]: Вызов dll функций с переменным числом параметров
От: Erop Россия  
Дата: 17.11.11 07:33
Оценка:
Здравствуйте, dandy, Вы писали:



D>Прости за оффтоп, но ты когда — нибудь спишь?

Раз в несколько дней
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[8]: Вызов dll функций с переменным числом параметров
От: Erop Россия  
Дата: 17.11.11 07:53
Оценка:
Здравствуйте, dandy, Вы писали:


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 функций с переменным числом параметров
От: dandy  
Дата: 17.11.11 09:10
Оценка:
Здравствуйте, Erop, Вы писали:


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 функций с переменным числом параметров
От: Кодт Россия  
Дата: 17.11.11 09:29
Оценка:
Здравствуйте, 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);
  return callee(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)
  push cookie
  push eax ; (return-to)
  ; теперь на стеке: (return-to) (cookie) (&arg1) (arg1) (arg2) ... (argN)
  jmp  callee
  ; по завершении - перейдём на (return-to) инструкцией ret 8 (очистив два своих аргумента)
  ; и оставим на стеке (arg1)...(argN)
  ; а вызывающая сторона почистит стек до argN уже сама
thunk endp

Аналогично делается для x64 и ARM.
(Только, насколько я помню, у арма stdcall такой же, как и fastcall, т.е. два первых аргумента передаются через регистры)
Перекуём баги на фичи!
Re[9]: Вызов dll функций с переменным числом параметров
От: dandy  
Дата: 17.11.11 09:37
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, 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);
К>  return callee(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)
К>  push cookie
К>  push eax ; (return-to)
К>  ; теперь на стеке: (return-to) (cookie) (&arg1) (arg1) (arg2) ... (argN)
К>  jmp  callee
К>  ; по завершении - перейдём на (return-to) инструкцией ret 8 (очистив два своих аргумента)
К>  ; и оставим на стеке (arg1)...(argN)
К>  ; а вызывающая сторона почистит стек до argN уже сама
К>thunk endp
К>

К>Аналогично делается для x64 и ARM.
К>(Только, насколько я помню, у арма stdcall такой же, как и fastcall, т.е. два первых аргумента передаются через регистры)

Ассемблер не знаю, увы, так что с этим связываться неохота.
Re[10]: Вызов dll функций с переменным числом параметров
От: Erop Россия  
Дата: 17.11.11 10:05
Оценка:
Здравствуйте, dandy, Вы писали:

D>В ассемблере я не силен к сожалению.

Сделай шаблонный или макросный пул функций-редеректоров...

D>Есть еще 3 — й вариант — чистый .NET


Если ты можешь само приложение переписывать, то в чём вообще запара? Сделай удобный интерфейс к плагинам (чтобы функция определлась ПАРОЙ указателей: указателем на код и указатеем на данные, который при вызове передаётся в эту самую указуемую функцию) и не страдай...

E>>Я вообще верно понял твою задачу?

D>

Мне так кажется, что если ты понятно расскажешь что делаешь, помочь теюе будет намного легче...

Да, и, кстати, объясни мне, зачем дотнет запускать в своём нативном процессе? Это какую вгоду приносит? Ну и в любом случае ком и так и так умеет. На дотнете ком-объекты пишутся стандартно, есть куча кода, который это поддерживает и облегчает, так что мне лично не понятно, зачем гонять через интерфейс плагина какие-то хреновины, а не комовские интерфейсы...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[11]: Вызов dll функций с переменным числом параметров
От: dandy  
Дата: 17.11.11 10:33
Оценка:
Здравствуйте, Erop, Вы писали:


D>>Есть еще 3 — й вариант — чистый .NET


E>Если ты можешь само приложение переписывать, то в чём вообще запара? Сделай удобный интерфейс к плагинам (чтобы функция определлась ПАРОЙ указателей: указателем на код и указатеем на данные, который при вызове передаётся в эту самую указуемую функцию) и не страдай...


Не могу я его переписать. Если мог бы, все было бы просто. Грузил бы .NET плагины из C++ managed dll. Мечты...

E>Мне так кажется, что если ты понятно расскажешь что делаешь, помочь теюе будет намного легче...


E>Да, и, кстати, объясни мне, зачем дотнет запускать в своём нативном процессе? Это какую вгоду приносит? Ну и в любом случае ком и так и так умеет. На дотнете ком-объекты пишутся стандартно, есть куча кода, который это поддерживает и облегчает, так что мне лично не понятно, зачем гонять через интерфейс плагина какие-то хреновины, а не комовские интерфейсы...


Нужно через мой плагин обеспечить максимально удобный .NET API для работы с прогой из пользовательских .NET библиотек классов. COM сложен в использовании, можно сделать намного проще для пользователя, поэтому он сразу отпадает.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.