Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2013.07.07;
Скачать: CL | DM;

Вниз

Можно ли с этим бороться?   Найти похожие ветки 

 
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;
Скачать: CL | DM;

Наверх




Память: 0.56 MB
Время: 0.009 c
1-1309449598
АлександрАл
2011-06-30 19:59
2013.07.07
Создание события?


3-1290592075
masterbloger
2010-11-24 12:47
2013.07.07
СУБД Cache + Delphi


3-1290496214
savinkin
2010-11-23 10:10
2013.07.07
oracle


15-1361565004
Юрий
2013-02-23 00:30
2013.07.07
С днем рождения ! 23 февраля 2013 суббота


15-1361374176
Pavia
2013-02-20 19:29
2013.07.07
Вычислить хулигана.