Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.01.29;
Скачать: [xml.tar.bz2];

Вниз

Сишные Указатели на функции и их интерпретация в Дельфи   Найти похожие ветки 

 
афвуд   (2004-01-14 15:50) [0]

В DLL(дельфийскую) передаётся в качестве параметра указатель на функцию из программы сишной. Получаю его так:

Type TGetVarFunction = function (ptr:Pointer;VarName:PChar):Variant;stdcall;
.................
procedure Exec(P:Pointer);stdcall;
var GetVar:TGetVarFunction;
..................
GetVar:=TGetVarFunction(p);


При вызове GetVar ошибка "External Exception". Никто не встречался?


 
Тимохов   (2004-01-14 16:03) [1]

может cdecl?


 
афвуд   (2004-01-14 16:05) [2]

>cdecl
А что это такое?


 
Тимохов   (2004-01-14 16:06) [3]

Ну ты пишешь же stdcall.
Почему именно stdcall?


 
афвуд   (2004-01-14 16:12) [4]

А у нас договоренность с тем кто пишет прогу(я DLL-ку пишу) ВСЕ функции адреса которых могут быть переданы в DLL будут stdcall - причём если я DLL пишу в С++ Билдере то всё путём.


 
Digitman   (2004-01-14 16:33) [5]

сдается мне, что С++ не знает никаких дельфийских "variant"


 
афвуд   (2004-01-14 16:34) [6]

Это С++ BUILDER. Он знает VCL.


 
афвуд   (2004-01-14 16:35) [7]

И Variant тоже. Мы его юзаем везде. И везде работает.


 
Skier   (2004-01-14 16:35) [8]

>афвуд © (14.01.04 16:34) [6]
А покажи-ка код полностью.


 
афвуд   (2004-01-14 16:43) [9]

А я почти всё показал.

Type TGetVarFunction = function (ptr:Pointer;VarName:PChar):Variant;stdcall;
.................
procedure Exec(P:Pointer);stdcall;
var GetVar:TGetVarFunction;
begin
..................
GetVar:=TGetVarFunction(p);
ShowMessage(GetVar(p,PChar("par")));//именно вот здесь ошибка,
{а если смотреть через CPU Window, то просто адрес по которому зовётся(call) функция, ведёт не туда куда надо.}
.....
end;


 
Тимохов   (2004-01-14 16:46) [10]

Интересно, а зачем адрес фукнции передавать как ее же параметр?
А вы уверены, что эта самая getvar не меняет VarName?


 
афвуд   (2004-01-14 16:50) [11]

>Интересно, а зачем адрес фукнции передавать как ее же параметр?
>А вы уверены, что эта самая getvar не меняет VarName?
Хм... даже не понимаю.. видать немного невнимательно смотрели код. Никакой передачи функцие указатель на саму себя нет.

Хорошо могу вместо последнего ShowMessage написать

GetVar(<Здесь ЛЮБОЙ ПОИНТЕР всё падает при ВЫЗОВЕ>,PChar("par"));

Всё равно ошибка.


 
icWasya   (2004-01-14 16:50) [12]

и немножко кода на Си


 
Тимохов   (2004-01-14 16:52) [13]


> Хм... даже не понимаю.. видать немного невнимательно смотрели
> код. Никакой передачи функцие указатель на саму себя нет.


GetVar:=TGetVarFunction(p);
ShowMessage(GetVar( p,PChar("par")));
Жирненьким это что?

Повторюсь: "А вы уверены, что эта самая getvar не меняет VarName?"


 
афвуд   (2004-01-14 16:52) [14]

typedef void (*Pointer);
Pointer a;
a=GetVar;
void (__stdcall *Exec)(void (*ptr));
Exec = (void(__stdcall *) (void (*ptr)))GetProcAddress(dllp, "_Exec");
if(Exec) Exec(a);


Примерно так..


 
афвуд   (2004-01-14 16:53) [15]

>GetVar:=TGetVarFunction(p);
>ShowMessage(GetVar(p,PChar("par")));
>Жирненьким это что?

Я просто написал p вместо того что я там передаю что сократило код :)


 
Тимохов   (2004-01-14 16:55) [16]

А саму GetVar?


 
Verg   (2004-01-14 16:57) [17]


> {а если смотреть через CPU Window, то просто адрес по которому
> зовётся(call) функция, ведёт не туда куда надо.}


Значит в Exec передается указатель не туда.


 
Digitman   (2004-01-14 17:08) [18]

а где SрareMem ?


 
Sli   (2004-01-14 17:08) [19]

Variant __stdcall GetVar(void * ptr, char * str)
{
.......
}

PS: я это тот кто пишет прогу которая вызывает Dll.


 
Тимохов   (2004-01-14 17:10) [20]

Повторюсь: "А вы уверены, что эта самая getvar не меняет второй параметр?"


 
афвуд   (2004-01-14 17:15) [21]

>Повторюсь: "А вы уверены, что эта самая getvar не меняет второй параметр?"

Я же говорю, что ошибка при ВЫЗОВЕ функции GetVar(она не успевает вообще ничего сделать)и ещё: реально я ей передаю совершенно другой укзатель, а p написал здесь для краткости.


 
AKul   (2004-01-14 17:26) [22]


> афвуд © (14.01.04 17:15) [21]


снасала ты писал:
> {а если смотреть через CPU Window, то просто адрес по которому
> зовётся(call) функция, ведёт не туда куда надо.}


Потом написал:

> Я же говорю, что ошибка при ВЫЗОВЕ функции GetVar( она не успевает вообще ничего сделать)



Так как это понимать? Уточни пожайлуста вызывается она или нет.
Если call ведет не туда куда надо, то проверь передаваемый указатель...


 
Тимохов   (2004-01-14 17:28) [23]

AKul © (14.01.04 17:26) [22]
Вот-вот, пусть ответит. Не один я непонимающий :)))

Мой диагноз, что вызов происходит, и в С просто меняется второй параметр.


 
Sli   (2004-01-14 17:37) [24]

все падает при попытке вызова функции по указателю.... выполнение уходит в непонятную область где кода вообще нет, там просто данные.
Самое интересное что адрес действительно левый ( дебагером смотрел), но в dll на входе он как раз тот что нужен и когда он слетает непонятно


 
AKul   (2004-01-14 17:40) [25]


> Sli (14.01.04 17:37) [24]



> Самое интересное что адрес действительно левый ( дебагером
> смотрел), но в dll на входе он как раз тот что нужен и когда
> он слетает непонятно


Выполни пошаговую отладку и найдешь в каком месте он портится.


 
Sli   (2004-01-14 17:49) [26]

> Выполни пошаговую отладку и найдешь в каком месте он портится.

В том то и дело отладчик борланда показывает что все хорошо указатель туда куда нужно, а прсмотр кода ( cpu view ) показывает что он прыгает не туда (не по тому адресу что в переменной)


 
Digitman   (2004-01-14 17:52) [27]


> он прыгает не туда


не городи ерунду
чудес не бывает


 
Тимохов   (2004-01-14 17:54) [28]

Думаю, что это типичная 17ая строка... :((
Вряд ли так можно помочь...


 
Sli   (2004-01-14 18:02) [29]

> не городи ерунду
> чудес не бывает

я тоже так думал :-) но как выясняется что так, может компилер что то не так понимает....

> Думаю, что это типичная 17ая строка...

что имеется ввиду ???


 
AKul   (2004-01-14 18:02) [30]

Постоянно следи за указателем (cpu view).

Посмотри на входе процедуры, после инициализации фрейма стека ([ebp+8] кажется)

Посмотри при вызове
будет что-то типа: (зависит от оптимизации и версии компилятора)
mov eax,[ebp+8]
...
push....
push...
call eax ;или call [ebp+8]

внимательнее смотри!


 
alex_***   (2004-01-14 18:03) [31]

В том то и дело отладчик борланда показывает что все хорошо указатель туда куда нужно, а прсмотр кода ( cpu view ) показывает что он прыгает не туда (не по тому адресу что в переменной)


Ну и отлаживайтесь принтами типа ShowMessage();


 
Семен Сорокин   (2004-01-14 18:06) [32]

<offtop>странно начинал афвуд, продолжает Sli.
передача эстафеты :)</offtop>


 
афвуд   (2004-01-14 18:19) [33]

Я не выключился просто молчу.

>Ну и отлаживайтесь принтами типа ShowMessage();

C этого я и начинал. НО всё гораждо глубже...


 
Sandman25   (2004-01-14 18:41) [34]

Наверное, я задам тупой вопрос, но все-таки. Разве не нужно как-то специально настраивать функцию, чтобы указатель на нее был не near, а far?
По-моему, даже есть директива far.


 
афвуд   (2004-01-14 19:02) [35]

Немного не в ту степь.
В Win32 об этом беспокоиться не надо. Это применяется в программировании под ДОС для доступа в другие сегменты памяти.


 
Тимохов   (2004-01-14 19:06) [36]

афвуд © (14.01.04 19:02) [35]
Про 17 строку. Я так понимаю это слэнг многих здесь. Имеется в виду, что ошибка совсем не в том месте, которое обсуждается и без дополнительного углубления в проблематику решить это не выйдет.


 
Ruslan   (2004-01-14 19:38) [37]

Hy я добавлю: может проблема в преобразовании типа процедуры, т.е. когда ты вызываеш процедуру - вместо прямого перехода, она идет по адресу хранящимуся в этой ячейке. Легко проверяется в отладчике.


 
Серега   (2004-01-15 09:22) [38]

Вы чего городите !!!

Программы работают в разных адресных пространствах !!!!


 
alex_***   (2004-01-15 09:24) [39]

Так никто и не спорит с этим...


 
AKul   (2004-01-15 09:44) [40]


> Серега (15.01.04 09:22) [38]
> Вы чего городите !!!
>
> Программы работают в разных адресных пространствах !!!!


Каждый процесс действительно имеет свое адресное пространство.
Но речь вроде бы идет не о разных процессах, а об приложении и DLL, а это одно адрессное пространство (DLL даже может быть промеппирована во все процессы.).


 
Ермак   (2004-01-15 12:01) [41]

Может быть такая штука. В Делфи процедурный тип - это по сути указатель, но поскольку он - неявный указатель, Дельфа может интерпретировать его по разному. Поэтому могут возникать глюки.

Я пробовал гонять разные варианты твоей процедуры, но без Си и ДЛЛ, просто в Делфи. И что интересно, выявился некоторый плюрализьм: МЫ МОЖЕМ ПИСАТЬ И ТАК, И ТАК, А ОНО ВСЕ РАВНО РАБОТАЕТ, ХОТЯ ВРОДЕ КАК НЕ ДОЛЖНО БЫ. Процедурный тип в Делфи - довольно мутная штука с точки зрения синтаксиса.

1)
procedure Exec(P:TGetVarFunction);stdcall;
var GetVar:TGetVarFunction;
begin
GetVar:= @p; //Да, да, именно так!
//По нашей с вами логике GetVar должно бы указывать после этого
//на адрес переменной p в стеке процедуры, но...
//практика показала обратное! этот вариант работает...
//и не хуже, чем GetVar := p;
GetVar(nil,PChar("par"));
end;

2)
//А вот тут не работает, хотя по сути ничем не отличается от
//предыдущей, передаем опять указатель!
procedure Exec(P:pointer);stdcall;
var GetVar:TGetVarFunction;
begin
GetVar:= @p; //Здесь уже не прокатит, потому что p - явно заданный указатель. И GetVar покажет фиг знает куда, но почему, спрашивается, в прошлый раз работало? Только потому, что тип
передаваемой переменной был описан по другому.
GetVar(nil,PChar("par"));
end;

3)
//А вот это работает снова.
procedure Exec(P:pointer);stdcall;
var GetVar:TGetVarFunction;
begin
GetVar:= p; //Никакого преобразования типа можно не делать
GetVar(nil,PChar("par"));
end;

ВЫВОД: Попробуй переписать так или этак. Особенно 3 вариант.
Может быть, когда работаем в связке с СИ, преобразование типа дает какой-то побочный эффект.
Или первый вариант с двумя подвариантами с @ и без @.

Короче говоря, синтанализатор Делфи иногда допускает такие вот глупости. ;-( По идее, из всех возможных вариантов только один будет синтаксически правильным. Ан нет! То ли это просто недосмотр, то ли для облегчения жизни чайникам сделано... Но в хорошем языке программирования такого плюрализма быть не должно.
В Си, например.


 
афвуд   (2004-01-15 13:38) [42]

>то ли для облегчения жизни чайникам сделано...

Мне кажется именно для этого и сделано.
В общем могу сказать только одно:
Переменная GetVar не меняется когда мы делаем
GetVar:= p;
Причём не меняется при любых вариациях(т.е. GetVar:=@p, @GetVar:= p;(как бы глупо не выглядели некторые конструкции я пробовал всё) и т.д.) И чего делать я пока не знаю...


 
Digitman   (2004-01-15 14:15) [43]


> афвуд © (15.01.04 13:38) [42]


а на кой шут вообще нужна тебе эта лок.переменная ?

вызывай напрямую :

TGetVarFunction = function(ptr:Pointer;VarName:PChar):Variant;stdcall;

procedure Exec(P:pointer); stdcall;
begin
TGetVarFunction(p)(nil, "par");
end;

если не уверен, что фактически переданный Р-параметр есть корректный адрес в корректном модуле, то можешь перед вызовом проверить :

procedure Exec(P:pointer); stdcall;
begin
if FindHInstance(P) <> 0 then
TGetVarFunction(p)(nil, "par")
else
ShowMessage("Переданный указатель " + IntToHex(P, 8) + " есть черт те что и черт те где находящееся, но только не адрес, принадлежащий одному из загруженных модулей текущего процесса");
end;


 
Digitman   (2004-01-15 14:20) [44]


> афвуд © (15.01.04 13:38) [42]


в догонку..

коль речь у тебя идет о стыке BCB и Делфи, то надеюсь, что передаешь ты действительно указатель на процедуру , а не на процедурный метод объекта ... хотя на упомянутую проблему это повлиять непосредственно не может ... "грабли" стукнут уже при выполнении того метода. адрес которого был передан


 
Ермак   (2004-01-15 16:34) [45]

>В общем могу сказать только одно:
>Переменная GetVar не меняется когда мы делаем
>GetVar:= p;
>Причём не меняется при любых вариациях(т.е. GetVar:=@p, >@GetVar:= p;(как бы глупо не выглядели некторые конструкции я >пробовал всё) и т.д.) И чего делать я пока не знаю...

Типа, как не меняется? Присваивания НЕ ПРОИСХОДИТ?!!
Бред собачий какой-то... Первый раз такое вижу...

Попробуй не присваиванием, а вот так:
Move(p, GetVar, SizeOf(pointer))

Или асеммблерную вставку с mov. Правда, точный синтаксис подзабыл.

asm
mov eax, p
mov GetVar, eax
end;

или вообще че нибудь по типу

asm
mov eax, p
call eax
end;

Пардон, если ошибся в Асме...


 
Ермак   (2004-01-15 16:45) [46]

А еще может быть...
Может из-за stdcall?
Там же в стеке в другом порядке параметры загоняются...
А при присваивании какая-то фигня возникает из-за этого?
Может такое быть?
По-моему нет, но все же...

Попробуй в проге на С не писать __stacall, т.е. оставить процедуру с сишным стандартом, а вот в Делфях вместо
stdcall написать cdecl - это значит, будет использоваться сишный стандарт (C DECLaration).

И еще, если мне память не изменяет, стандарт stdcall, который юзает ВИнда, предусматривает еще дополнительный тип CALLBACK,
с которым нужно компилить процедуры, кторые будут вот так вызываться, через указатель между прогой и ДЛЛ...
В Делфи это не юзается, там даже слова такого нет - callback,
а вот в C++ всегда это слово добавляется перед коллбэчными :) процедурами. Вспомни ВИНАПИ функции, где мы им какую-нибудь процедуру свою передаем - там всегда тип процедуры CALLBACK.
ЧЕстно говоря, я в Си это никогда не писал, поэтому не скажу точно, но надо что-то типа
void __stdcall CALLBACK proc()

или
void WINAPI CALLBACK proc()

Еще фишка... Я в Си не мастер, но знаю точно, что эквивалент Дельфяцкому stdcall в Си - это именно WINAPI. Может, stadcall в Си - это не то же самое?


 
AKul   (2004-01-15 16:45) [47]


> афвуд © (15.01.04 13:38) [42]

> Переменная GetVar не меняется когда мы делаем
> GetVar:= p;
> Причём не меняется при любых вариациях(т.е. GetVar:=@p,
> @GetVar:= p;(как бы глупо не выглядели некторые конструкции
> я пробовал всё) и т.д.) И чего делать я пока не знаю...


Быть такого не может! Разве что оптимизатор посчитал, что переменная GetVar не используется после присваивания, и выкинул присваивание.

В любом случае, посмотри во что компилируется строка GetVar:=P (в окне CPUView). Можешь прислать сюда этот кусок ассемблерного кода сюда.


 
Striker   (2004-01-16 20:00) [48]


> И еще, если мне память не изменяет, стандарт stdcall, который
> юзает ВИнда, предусматривает еще дополнительный тип CALLBACK,
> с которым нужно компилить процедуры, кторые будут вот так
> вызываться, через указатель между прогой и ДЛЛ...


Если мне не изменяет мой склероз, то в C/C++ CALLBACK, равно как и WINAPI, эквивалентны дерективе __stdcall. Это, по идее, макрос препроцессора, что-то типа #define CALLBACK __stdcall. Так что разницы вроде быть не должно.


 
афвуд   (2004-01-19 11:21) [49]

Народ, ошибка видать где-то совсем в непонятном месте. Просто написал другую дельфийскую библиотеку и там ВСЁ ЭТО РАБОТАЕТ. Всем спасибо за советы. Я думаю этот баг я как-нибудь выловлю.



Страницы: 1 2 вся ветка

Форум: "Основная";
Текущий архив: 2004.01.29;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.58 MB
Время: 0.007 c
1-93443
Интересующийся
2004-01-16 13:37
2004.01.29
Определить символ с цветом


14-93675
raidan
2004-01-07 01:08
2004.01.29
А почему у некоторых имя как ссылка на e-mail?


6-93616
Dmitry The Wing
2003-11-24 10:44
2004.01.29
Как соединить модемом две машины? (дозвон, прием звонка)


3-93349
Jane
2004-01-02 18:23
2004.01.29
В DBGrid не отображается знаечние поля.


4-93733
frost
2003-11-02 20:12
2004.01.29
---|Ветка была без названия|---





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский