Форум: "Прочее";
Текущий архив: 2009.09.06;
Скачать: [xml.tar.bz2];
ВнизФункция обратного вызова с переменным числом параметров. Найти похожие ветки
← →
DVM © (2009-07-07 02:15) [0]Имеется некая dll, написанная на С.
В качестве параметра одна из функций этой dll принимает указатель на функцию обратного вызова:
__declspec(dllexport) void Start(бла-бла, бла-бла,
void (__cdecl *ShowDebug)(int Level, struct ItemStruct *Item, WCHAR *Message, ...),
бла-бла, бла-бла);
, здесь бла-бла - прочие параметры функции Start, не имеющие отношения к делу. ShowDebug() и есть та функция обратного вызова, которую будет вызывать dll.
В функции ShowDebug переменное число параметров, что вызвало у меня затруднения при попытке прикрутить работу с этой dll из программы на Delphi.
Функция ShowDebug в программе на Delphi выглядит так:
procedure ShowDebug(Level: Integer; Item: PItemStruct; Msg: PWChar); cdecl;
begin
//
end;
Очевидно, что так хоть и работает, но я теряю параметры после Msg. Исправление на традиционный для паскаля вид:
procedure ShowDebug(Level: Integer; Item: PItemStruct; Msg: PWChar; Arg: array of const); cdecl;
begin
//
end;
Приводит к ошибке.
Конечно можно плюнуть на эти параметры и обойтись и без них, но ме все же интересно как мне их получить в программе на Delphi?
← →
dmk © (2009-07-07 04:04) [1]Возможно поможет
http://www.progz.ru/forum/index.php?showtopic=25598
← →
SPeller © (2009-07-07 04:22) [2]varargs ?
← →
SPeller © (2009-07-07 04:23) [3]
> When importing a C function that takes a variable number
> of parameters, use the varargs directive. For example,
>
> function printf(Format: PChar): Integer; cdecl; varargs;
>
← →
DVM © (2009-07-07 11:19) [4]
> SPeller
Близко, но не совсем то.
Дело в том, что я НЕ ИМПОРТИРУЮ функцию С с переменным числом параметров.
В моем случае DLL написанная на C должна вызывать функцию из программы на Delphi, передавая ей переменное число параметров.
Куда приткнуть varargs я че-то не понимаю.
← →
clickmaker © (2009-07-07 12:30) [5]> передавая ей переменное число параметров
а если 2 параметра: количество параметров и массив параметров следом?
← →
DVM © (2009-07-07 12:43) [6]
> clickmaker ©
> а если 2 параметра: количество параметров и массив параметров
> следом?
Т.е. предлагаешь функцию описать так:
procedure ShowDebug(Level: Integer; Item: PItemStruct; Msg: PWChar; n: byte; arg: array of const); cdecl;
begin
//
end;
Access Violation все равно.
Если программу писать на СИ, то в ней легко описать данную функцию так и все работает:
void __cdecl ShowDebug(int Level, struct ItemStruct *Item, WCHAR *Format, ...) {
va_list VarArgs;
....
}
Самое интересное, что во FreePascal конструкция вида тоже работает:
procedure ShowDebug(Level: Integer; Item: PItemStruct; Msg: PWChar; Arg: array of const); cdecl;
begin
//
end;
А В ДЕЛФИ НЕТ!!!
← →
clickmaker © (2009-07-07 12:57) [7]> [6] DVM © (07.07.09 12:43)
не совсем. При смешении языков нужно какие-то всем понятные типы использовать. Массив указателей, целых и т.п. Может, VARIANT? Только не дельфийский, а COMовский.
← →
tesseract © (2009-07-07 13:04) [8]
> arg: array of const); cdecl;
А чем ссылка-то просто не устраивает? Зачем open array гонять ? Если имеено массив непонятно чего нужно - то PSafeArray отлично подходит плюс ещё и потокобезопасен.
← →
oxffff © (2009-07-07 13:09) [9]Передача
> arg: array of const
Развернется в два параметра.
Указатель на данные + верхняя граница массива.
+ придется коректно заполнить TVarRec на стороне С.
← →
DVM © (2009-07-07 13:11) [10]
> clickmaker ©
> При смешении языков нужно какие-то всем понятные типы использовать.
Но дело в том, что DLL использует описанный выше метод передачи параметров, на который я повлиять не могу. Точнее можно переделать DLL, благо исходники доступны, но не хотелось бы, т.к. она чужая и решать переделывать ее или нет должен ее автор.
Как я думаю, что сишная DLL все же эти параметры моей функции передает, т.к. при таком описании:
procedure ShowDebug(Level: Integer; Item: PItemStruct; Msg: PWChar); cdecl;
ошибок не возникает, но откуда их забрать?
← →
DVM © (2009-07-07 13:15) [11]
> tesseract © (07.07.09 13:04) [8]
> Зачем open array гонять ?
Его как раз гонять не получается, т.к. с ним сразу AV
> Если имеено массив непонятно чего нужно - то PSafeArray
> отлично подходит плюс ещё и потокобезопасен.
т.е. ты предлагаешь последний параметр функции сделать PSafeArray?
> oxffff © (07.07.09 13:09) [9]
> + придется коректно заполнить TVarRec на стороне С.
Ннереально. т.к. DLL неприкасаема, будем считать.
← →
oxffff © (2009-07-07 13:17) [12]
> > oxffff © (07.07.09 13:09) [9]
>
>
> > + придется коректно заполнить TVarRec на стороне С.
>
> Ннереально. т.к. DLL неприкасаема, будем считать.
Поэтому у тебя и AV.
← →
DVM © (2009-07-07 13:20) [13]
> oxffff ©
> Поэтому у тебя и AV.
Да это понятно. Но, думаю, решение можно найти.
← →
oxffff © (2009-07-07 13:21) [14]
> DVM © (07.07.09 13:11) [10]
Какой параметр говорит сколько параметров передано
int Level
struct* ItemStruct
?
← →
oxffff © (2009-07-07 13:22) [15]
> Но, думаю, решение можно найти.
Конечно. Сейчас найдем. ;)
← →
DVM © (2009-07-07 13:24) [16]
> oxffff ©
> Какой параметр говорит сколько параметров передано
В том то и дело, что никакой из этих параметров не связан с количеством передаваемых далее параметров.
← →
oxffff © (2009-07-07 13:25) [17]
> DVM © (07.07.09 13:24) [16]
Так не бывает. Как ты узнаешь где граница?
← →
tesseract © (2009-07-07 13:27) [18]
> т.е. ты предлагаешь последний параметр функции сделать PSafeArray?
Я вообще предлагал тупо указателем объявлять, но можно и SafeArray. Правда придёться выяснять как он в с-ях оперируется.
> ошибок не возникает, но откуда их забрать?
Из памяти конечно :-)
← →
DVM © (2009-07-07 13:30) [19]
> oxffff © (07.07.09 13:25) [17]
> Как ты узнаешь где граница?
Дело в том, что в Delphi я никак не узнаю, потому как в функцию Delphi передать переменное количество параметров из DLL на СИ у меня бы не получилось.
Если бы программа была на СИ, то там бы я делал так:
void __cdecl ShowDebug(int Level, struct ItemStruct *Item, WCHAR *Format, ...) {
va_list VarArgs;
....
va_start(VarArgs,Format);
vswprintf_s(......., Format,VarArgs);
va_end(VarArgs);
}
О том, сколько элементов в VarArgs очевидно делается предположение по количеству символов для подстановки в Format
← →
DVM © (2009-07-07 13:31) [20]
> tesseract © (07.07.09 13:27) [18]
> Я вообще предлагал тупо указателем объявлять
Это тоже первое, что пришло мне в голову. И это прокатывает. Но как потом разобрать какие параметры там вот вопрос.
← →
oxffff © (2009-07-07 13:36) [21]
> DVM © (07.07.09 13:30) [19]
Технически тебе никто не мешает сделать ASM вставки.
Транслируя вызов в
вызов delphi функции с более адекватной сигнатурой например.
Level:integer;Item:pItemStruct;VariableLengthDATA:pointer) ;
Дальше ты можешь ее анализировать как хочешь. Это можно сделать.
← →
oxffff © (2009-07-07 13:44) [22]to DVM
Вот пример.
procedure NativeDelphiProc(a:integer;p:pinteger);
var i:integer;
begin
showmessage(inttostr(a));
{$POINTERMATH ON}
for i := 0 to 2 do
begin
showmessage(inttostr(p[i]));
end;
{$POINTERMATH OFF}
end;
procedure VarProc(a:integer;b:integer;c:integer;d:integer);cdecl;
asm
mov eax,[esp+8];
lea edx,[esp+12]
call NativeDelphiProc;
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
//Вызов со стороны C++
VarProc(1,2,3,4);
end;
P.S.Пойду прогуляться. Скоро вернусь к диалогу. :)
← →
DVM © (2009-07-07 13:51) [23]
> oxffff © (07.07.09 13:44) [22]
Спасибо
← →
oxffff © (2009-07-07 15:34) [24]
> DVM © (07.07.09 13:51) [23]
Вопрос исчерпан?
← →
DVM © (2009-07-07 15:52) [25]
> oxffff © (07.07.09 15:34) [24]
> Вопрос исчерпан?
Нет, не совсем, я ждал возвращения с прогулки :) Направление движения понятно, как я и догадывался без ASM тут не обойтись.
В примере [22] мне не совсем понятно, где же это самое переменное количество параметров.
Функция из программы на СИ вызвается ровно с теми параметрами, которые объявлены в Pas коде. Их там ровно 4 и передается 4. Но как поправить PAS код, чтобы передавать 5 6 и т.д. параметров. Лучше на примере моих конкретных функций:
Еще раз функция в программе на паскале:
procedure ShowDebug(Level: Integer; Item: PItemStruct; Msg: PWChar); cdecl;
begin
//
end;
← →
oxffff © (2009-07-07 16:04) [26]
> DVM © (07.07.09 15:52) [25]
У тебя вызов Delphi из С++ с передачей различного числа параметров.
Технически параметры могут быть произвольного типа. Тогда нужно использовать
procedure NativeDelphiProc(a:integer;RawParams:Pointer) для варьируемых параметров произвольного типа ;
Если варьируемые параметры одного типа,
то тогда RawParams:PsomeType);
А дальше обращаешься к параметрам как
RawParams[0],
RawParams[1]
RawParams[2] и т.д.
То есть у функции есть обязательная часть и необязательная(варьируемая часть). К обязательным параметрам как обычно. А к не обязательным через массив(для удобства).
← →
oxffff © (2009-07-07 16:06) [27]
> DVM © (07.07.09 15:52) [25]
Напиши сигнатуру параметров обязательной части.
и сигнатуру параметров необязательной части.
← →
DVM © (2009-07-07 16:22) [28]
> Напиши сигнатуру параметров обязательной части.
Собственно, вот эти три параметра выше - они обязательные
Я думаю расписывать PItemStruct нет смысла, так как это все одно указатель,
PWChar тоже указатель, фактически PWideChar.
Необязательные параметры - это либо указатели на строки, либо целые числа, либо числа UINT64 либо Double. И их переменное количество. По идее, они потом должны быть в функции ShowDebug подставлены в строку Msg так как это делает функция Format.
← →
oxffff © (2009-07-07 17:21) [29]
> DVM © (07.07.09 16:22) [28]
Тогда указатель на rawData.
Где ты сам парсишь на составные параметры.
Только как найдешь метаописания типов?
В format за тебя делает компилятор через TVarRec.
← →
Игорь Шевченко © (2009-07-07 17:50) [30]если функция cdecl, ты ее можешь объявлять только с обязательными параметрами, включая msg, но с модификатором cdecl.
После этого, в начале своей программы делаешь ассемблерную вставку и имитируешь работу printf, разбирая msg, в котором, как я больше чем уверен, написаны спецификации формата вывода в стиле printf. После этого, зная, каким спецификациям соответствуют какие типы (а главное, размер значений этих типов), аккуратно получаешь адреса остальных параметров через @Msg + вычисленное смещение для конкретного аргумента.
← →
DVM © (2009-07-07 17:51) [31]
> oxffff ©
> Только как найдешь метаописания типов?
Можно попробовать полагаться на их описания в Msg, там же указан тип, например %d. Это конечно не очень удобно и не очень надежно, но все лучше чем ничего.
P.S. Все больше склоняюсь к тому, чтобы переделать dll таким образом чтобы она сама подставляла эти параметры в строку MSG. Или сделать еще одну dll на СИ, которая бы стала промежуточным звеном между программой на паскале и этой первоначальной dll.
← →
DVM © (2009-07-07 18:02) [32]
> Игорь Шевченко © (07.07.09 17:50) [30]
> в котором, как я больше чем уверен, написаны спецификации
> формата вывода в стиле printf.
Именно так.
> ты ее можешь объявлять только с обязательными параметрами,
> включая msg, но с модификатором cdecl.
Т.е. мое объявление как:
procedure ShowDebug(Level: Integer; Item: PItemStruct; Msg: PWChar); cdecl;
Оно в данном случае и есть единственно верное?
> После этого, в начале своей программы делаешь ассемблерную
> вставку
Вот с этим то у меня проблема.
← →
palva © (2009-07-07 18:24) [33]Можно ведь и без ассемблера обойтись. Взять адрес последнего описанного параметра и наращивать при помощи обычной целой арифметики. Выйдем на хвост необязательных параметров. Вот здесь предлагается некий код. Думаю, полезно его посмотреть, чтобы не наткнуться на подводные камни.
http://stackoverflow.com/questions/298373/how-can-a-function-with-varargs-retrieve-the-contents-of-the-stack/298603
← →
DVM © (2009-07-07 18:46) [34]
> palva ©
> Взять адрес последнего описанного параметра и наращивать
> при помощи обычной целой арифметики.
Это мысль. Попробую, спасибо за ссылку.
← →
Игорь Шевченко © (2009-07-07 19:13) [35]
> Или сделать еще одну dll на СИ, которая бы стала промежуточным
> звеном между программой на паскале и этой первоначальной
> dll.
Это лучше всего
← →
oxffff © (2009-07-07 22:35) [36]
> DVM © (07.07.09 17:51) [31]
>
> > oxffff ©
>
>
> > Только как найдешь метаописания типов?
>
> Можно попробовать полагаться на их описания в Msg, там же
> указан тип, например %d. Это конечно не очень удобно и не
> очень надежно, но все лучше чем ничего.
Тогда у тебя все есть чтобы решить эту задачу.
← →
DVM © (2009-07-07 23:13) [37]
> oxffff ©
> Тогда у тебя все есть чтобы решить эту задачу.
Да, теперь есть. Да собственно по ссылке [33] практически и есть решение моей задачи, разве что строка Msg у меня сложнее.
--------------------------
Всем спасибо за помощь. На мой взгляд, вопрос был заслуживающий внимания.
← →
Игорь Шевченко © (2009-07-08 00:11) [38]DVM © (07.07.09 23:13) [37]
> На мой взгляд, вопрос был заслуживающий внимания
Безусловно.
Но наиболее правильным решением в данном случае является написание промежуточной DLL на С, которая преобразовывает callback с переменными числом параметров в callback с фиксированным числом параметров, используя для этого функцию swprintf
← →
Германн © (2009-07-08 00:53) [39]
> Игорь Шевченко © (08.07.09 00:11) [38]
>
> DVM © (07.07.09 23:13) [37]
>
>
> > На мой взгляд, вопрос был заслуживающий внимания
>
>
> Безусловно.
>
И что ещё было наиболее естественно (и правильно на сём форуме) вопрос был помещен в "Прочее".
← →
DVM © (2009-07-08 12:13) [40]
> Игорь Шевченко © (08.07.09 00:11) [38]
> Но наиболее правильным решением в данном случае является
> написание промежуточной DLL
Написал промежуточную Dll, все отлично заработало.
Страницы: 1 2 вся ветка
Форум: "Прочее";
Текущий архив: 2009.09.06;
Скачать: [xml.tar.bz2];
Память: 0.56 MB
Время: 0.007 c