Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 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
2-1352803524
Павел Калугин
2012-11-13 14:45
2013.07.07
Подскажите как правильно работать с библиотеками BPL


15-1361442914
Dimka Maslov
2013-02-21 14:35
2013.07.07
Можно ли с этим бороться?


1-1309850189
adigozelov
2011-07-05 11:16
2013.07.07
ESC-команд Epson Lq 300,


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


15-1361224437
Германн
2013-02-19 01:53
2013.07.07
Компьютер с Win7 ни с того ни с сего, вдруг, отказывается спать.





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский