Форум: "Прочее";
Текущий архив: 2013.07.07;
Скачать: [xml.tar.bz2];
ВнизМожно ли с этим бороться? Найти похожие ветки
← →
Dimka Maslov © (2013-02-21 14:35) [0]Если я на С++ напишу заголовок функции
IUnknown* __stdcall Func()
это означает, что функция вызращает через eax указатель на IUnknown.
Но если я в Delphi напишуfunction Func: IUnknown stdcall;
это уже будет означать, что функция записывает указатель на IUnknown в переменную, адрес которой передан через стек, т.е. в терминах C++void __stdcall Func(void** Result)
Чтобы подружить сишную библиотеку с дельфийской прогой приходится учитывать это обстоятельство объявлением функцииfunction Func: Pointer stdcall;
c последующим явным преобразованием типа результата к IUnknown
Есть ли способ заставить Delphi так не делать, и функции в типе результата которых указан интерфейс оставлять такими, какими они объявлены в явном виде?
← →
брат Птибурдукова (2013-02-21 14:54) [1]
> Если я на С++ напишу заголовок функцииIUnknown* __stdcall
> Func()это означает, что функция вызращает через eax указатель
> на IUnknown.
Странно. Насколько я знаю, stdcall передачи параметров в регистрах не подразумевает. Ты с fastcall не путаешь?
← →
Игорь Шевченко © (2013-02-21 15:30) [2]
> IUnknown* __stdcall Func()
> это означает, что функция вызращает через eax указатель
> на IUnknown.
Что соответствует Delphi-йскомуtype
PIUnknown = ^IUnknown;
function Func: PIUnknown; stdcall;
← →
Dimka Maslov © (2013-02-21 16:12) [3]
> брат Птибурдукова (21.02.13 14:54) [1]
Результат всё равно передаётся только через eax
← →
Dimka Maslov © (2013-02-21 16:34) [4]
> Игорь Шевченко © (21.02.13 15:30) [2]
Всё равно не работает.
← →
Игорь Шевченко © (2013-02-21 16:45) [5]
> Всё равно не работает.
мало информации
← →
DevilDevil © (2013-02-21 16:50) [6]> Dimka Maslov © (21.02.13 14:35)
всё дело в том, что IUnknown это сложный тип, которому автоматически вызываются AddRef и Release. А по правилам С++ все эти вещи нужно вызывать вручную. Кроме того важно понимать, что IUnknown в Delphi = IUnknown* в С++
Попробуй так:function __Func: Pointer stdcall; external dll name "Func"
function Func: IUnknown;
begin
Result := IUnknown(__Func()); // здесь должно правильно вызваться AddRef
end;
← →
Dimka Maslov © (2013-02-21 17:04) [7]
> Игорь Шевченко © (21.02.13 16:45) [5]
Если я объявляю func: PIUnknown в Delphi и IUnknown* Func в С++. То а) в Delphi получается значение, не равное тому, что возвращается из C++ б) всё заканчивается AV
> DevilDevil © (21.02.13 16:50) [6]
Это я знаю и так и делаю.
← →
DevilDevil © (2013-02-21 17:08) [8]> Это я знаю и так и делаю.
так а в чём вопрос ?
это принципиально разные типы. В С++ это просто указатель. В Delphi это сложный тип, который управляется особым образом. Последний параметр в функциях - это лишь частный случай.
Строки (string) и динамические массивы (array of) - это тоже всего лишь указатели. Но в Delphi в случае функции - они всегда указываются последним параметром
← →
Dimka Maslov © (2013-02-21 17:22) [9]
> так а в чём вопрос ?
Есть ли другая возможность сделать этот тип простым указателем, например какая-нибудь директива компилятора.
Строка, хотя и является «сложным» типом, тем не менее из функции возвращается через eax и подсчёт ссылок и финализация при этом нормально работают.
← →
Игорь Шевченко © (2013-02-21 17:51) [10]вот пример:
type
PIUnknown = ^IUnknown;
var
Intf: IUnknown;
function Foo: PIUnknown;
begin
Intf := TInterfacedObject.Create;
Result := @Intf;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
I: IUnknown;
begin
I := Foo^;
if Supports(I, IUnknown) then
ShowMessage("Supports");
end;
глобальная переменная сделана, чтобы избавиться от вызова _IntfClear по выходе из функции Foo. Внутри Foo выполняется _IntfCopy, которая вызывает _AddRef
Так как я не знаю, что делает функция на С, то никаких рекомендаций дать не могу
← →
Игорь Шевченко © (2013-02-21 17:52) [11]Можно объявить function Foo: PIUnknown; stdcall;
результат не меняется
← →
Dimka Maslov © (2013-02-21 17:59) [12]
> Игорь Шевченко © (21.02.13 17:51) [10]
Можно просто написать function Foo: IUnknown и всё будет нормально, но только до тех пор, пока мы в Delphi. Как только приплетается сишный код - всё перестаёт работать, если не принять соотв. мер.
← →
Игорь Шевченко © (2013-02-21 18:02) [13]Dimka Maslov © (21.02.13 17:59) [12]
Ну так прими меры к вызову _AddRef
← →
DevilDevil © (2013-02-21 18:03) [14]> Есть ли другая возможность сделать этот тип простым указателем,
> например какая-нибудь директива компилятора.
> Строка, хотя и является «сложным» типом, тем не менее из
> функции возвращается через eax и подсчёт ссылок и финализация
> при этом нормально работают.
нет, такой директивы в Delphi нет
← →
Dimka Maslov © (2013-02-21 18:05) [15]
> Ну так прими меры к вызову _AddRef
Проблема не в _AddRef, а в том, что функции, возвращие указатель на интерфейс - разные с точки зрения двух компиляторов, хотя объявлены «одинаково».
← →
Dimka Maslov © (2013-02-21 18:06) [16]
>
> нет, такой директивы в Delphi нет
А жаль.
← →
Игорь Шевченко © (2013-02-21 18:18) [17]Dimka Maslov © (21.02.13 18:05) [15]
http://rvelthuis.de/articles/articles-cppobjs.html
?
← →
Владислав © (2013-02-21 18:27) [18]
> Игорь Шевченко © (21.02.13 15:30) [2]
>
> > IUnknown* __stdcall Func()
> > это означает, что функция вызращает через eax указатель
>
> > на IUnknown.
>
>
> Что соответствует Delphi-йскому
>
> type
> PIUnknown = ^IUnknown;
>
> function Func: PIUnknown; stdcall;
Все таки IUnknown* соответствует в Delphi IUnknown.
← →
Dimka Maslov © (2013-02-21 18:42) [19]
> Игорь Шевченко © (21.02.13 18:18) [17]
Предлагаемые там решения подразумевают возможность внесения изменений в сишный код. А она есть ен всегда.
← →
DevilDevil © (2013-02-21 18:47) [20]
> Проблема не в _AddRef, а в том, что функции, возвращие указатель
> на интерфейс - разные с точки зрения двух компиляторов,
> хотя объявлены «одинаково».
> нет, такой директивы в Delphi нет
>
> А жаль.
не стоит огорчаться
это касается лишь ситуаций когда IInterface возвращается результатом
в остальных случаях всё остаётся без изменений
← →
Dimka Maslov © (2013-02-21 19:02) [21]
> DevilDevil © (21.02.13 18:47) [20]
Через Pointer работает, а раз другого способа нет - пусть останется через Pointer. Главное потом не забыть к какому типу его приводить. Опять же приходится плодить лишние сущности...
← →
Вагонка (2013-02-21 19:48) [22]А register или cdecl не помогают?
← →
Dimka Maslov © (2013-02-21 20:31) [23]
> Вагонка (21.02.13 19:48) [22]
модификатор вызова определяет порядок передачи параметров в стек и очистки стека. То, как формируется этот список этими соглашениями не описываются.
← →
Inovet © (2013-02-21 20:59) [24]> [23] Dimka Maslov © (21.02.13 20:31)
> То, как формируется этот список этими соглашениями не описываются.
Раз 7 перечитал, не понял что за список и что за его формирование.
← →
Dimka Maslov © (2013-02-21 21:05) [25]
> Inovet © (21.02.13 20:59) [24]
Формирование списка параметров функции (что туда попадёт) не зависит от модификатора вызова.
← →
Inovet © (2013-02-21 21:20) [26]> [25] Dimka Maslov © (21.02.13 21:05)
В смысле, что указал, то и попадёт? Ну так а как иначе.
← →
Dimka Maslov © (2013-02-21 21:33) [27]
> В смысле, что указал, то и попадёт? Ну так а как иначе.
Некоторые параметры передаются неявно
← →
Inovet © (2013-02-21 21:46) [28]> [27] Dimka Maslov © (21.02.13 21:33)
> Некоторые параметры передаются неявно
Например какие?
← →
DVM © (2013-02-21 21:59) [29]
> Dimka Maslov © (21.02.13 14:35)
я не большой знаток COM, но имхо делать функции, возвращающие интерфейс не очень хорошо. Правильная с точки зрения COM функция должна выглядеть не как:
function Func: IUnknown;
а так:
function Func(var/out Result: IUnknown): HRESULT;
← →
Игорь Шевченко © (2013-02-21 22:29) [30]Inovet © (21.02.13 21:46) [28]
> Например какие?
http://stackoverflow.com/questions/8518992/function-returning-record-with-interface-field
http://rvelthuis.de/articles/articles-convert.html
← →
Inovet © (2013-02-21 22:39) [31]> [30] Игорь Шевченко © (21.02.13 22:29)
Ну и что. Всегда известно, что там передано будет - то, что описано и ничего другого.
← →
DevilDevil © (2013-02-21 23:23) [32]> DVM © (21.02.13 21:59) [29]
классная идея
ты про safecall и stdcall
НО!
допустим:function __Func: Pointer stdcall; external dll name "Func";
function Func: IUnknown; // procedure(var Result: IUnknown);
begin
Result := IUnknown(__Func());
end;
I := old_value;
I := Func();
В таком случае не просто проинициализируется I и вызовет ему AddRef, в этом случае у old_value так же вызовется Release !
Если объявить safecall в C++, то просто проинициализируется указатель, а old_value не обнулится
← →
Игорь Шевченко © (2013-02-21 23:45) [33]Inovet © (21.02.13 22:39) [31]
> Ну и что. Всегда известно, что там передано будет - то,
> что описано и ничего другого.
Например, методам объекта передается (неявно) указатель на экземпляр объекта :) Методам класса - указатель на класс. Тоже неявно. Функциям, возвращающим сложный тип по значению, а не по ссылке - неявный параметр для результата.
← →
Inovet © (2013-02-22 04:40) [34]> [33] Игорь Шевченко © (21.02.13 23:45)
Они и описаны неявно, и всегда известно, какой тип и в каком месте передан. Ну я уже понял, что хотел сказать Dimka Maslov. Именно это и хотел - модификаторы вызова влияют только на способ и порядок передачи параметров, на сами параметры не влияют. Т.е. в контексте сабжа, надо правильно указать тип, и вызов будет одинаковым и в Си++ и в Делфи.
← →
Dimka Maslov © (2013-02-24 21:03) [35]
> DVM © (21.02.13 21:59) [29]
При работе с внешними и удалёнными серверами - только через параметр. Но когда сервер гарантировано внутренний (фабрика класса вызывается не через DllGetClassObject, а через совсем другую функцию), интерфейс превращается всего-оишь в абстрактный класс. А тут уже лишние навороты не нужны.
Страницы: 1 вся ветка
Форум: "Прочее";
Текущий архив: 2013.07.07;
Скачать: [xml.tar.bz2];
Память: 0.53 MB
Время: 0.003 c