Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Переменные процедурного типа [D7, XP]


Страницы:   1 2 3

checkmate-maker ©   (2008-10-14 12:45:00) 

Здравствуйте, знатоки.
 Помогите, пожалуйста, разобраться с задачей проверки корректности присваивания.
 Имеется код:

...
var
 f: procedure(a0: Integer; a1:String); stdcall;
begin
 @f := GetPtr();
end;

 Функция GetPtr возвращает указатель на процедуру(либо функцию). Если параметры процедуры f идентичны параметрам в возвращенной процедуры, то все нормально. Если совпадение не достигнуто, то ненормально. Как до вызова f определить корректность параметров?
 Спасибо.


Сергей М.   (2008-10-14 15:41:00) [21]


> checkmate-maker   (14.10.08 15:29) [28]


Т.е. ты таки движешься по пути изобретения велосипеда)

Тогда уж, чтобы меньше возни было и для пущей универсальности:

function CallProcByName(AProcName, AParams: OleVariant): OleVariant; safecall;


oxffff   (2008-10-14 15:36:00) [22]


> Сергей М. ©   (14.10.08 15:32) [29]


Дык, и в вашем случае тоже самое.
В любом случае при расширении функции придется менять ее реализацию и место вызова. Хотите сказать что в вашем случае не так?


oxffff   (2008-10-14 15:33:00) [23]


> checkmate-maker   (14.10.08 15:29) [28]


Главное, чтобы работало. :)


Сергей М.   (2008-10-14 15:32:00) [24]


> oxffff ©   (14.10.08 15:23) [27]


Не пойдет.
При любом чихе править придется и вызываемую и вызывающую сторону.


checkmate-maker   (2008-10-14 15:29:00) [25]

Спасибо Всем за участие в дискуссии.
Воспользоюсь тем, что параметры процедур в библиотеке храняться в БД(об этом я промолчал намеренно - без обид), создам фунцию, следующего вида
function MayConnectToFunc(aFuncIdent: WideString; aParamArray: array of String; aIsFunc: Boolean = False): Boolean;
здесь aFuncIdent - точка входа в процедуру(параметр, который я использую при вызове GetPtr, описанный выше);
aParamArray - массив с типами параметров в согласовании с порядком следования; Также можно использовать TStringList.
aIsFunc-флажок, что это функция и последнее значение в массиве - это тип возвращаемого значения.


oxffff   (2008-10-14 15:23:00) [26]


> Сергей М. ©   (14.10.08 15:16) [26]


Могу упростить решение до минимума.

TCallContext=class
end;

TCallContextIntegerAndString=class
a:integer;
b:string;
end;

procedure Myfunc(a:TCallContext);
begin
if a is TCallContextIntegerAndStringthen
 else
 begin
 Showmessage('Not valid context');
 exit;
 end;
end;


Сергей М.   (2008-10-14 15:16:00) [27]


> checkmate-maker   (14.10.08 15:00) [22]


Проверку на соответствие кол-в и типов ожидаемых и фактически переданных параметров можно отдать на откуп любому готовому механизму маршаллинга диспинтерфейсных вызовов. При несовпадении он возбудит соответствующее исключение.


oxffff   (2008-10-14 15:10:00) [28]


> Сергей М. ©   (14.10.08 15:09) [24]


А...
Дык я стараюсь не ограничиваться одним вариантом решения. :)


Сергей М.   (2008-10-14 15:09:00) [29]


> oxffff ©   (14.10.08 15:00) [23]

Я про [15])


oxffff   (2008-10-14 15:00:00) [30]


> Сергей М. ©   (14.10.08 14:58) [21]


oxffff ©   (14.10.08 14:46) [16]
oxffff ©   (14.10.08 14:58) [20]

Штатно реализуются в D7.

P.S. Жаль что вы только про сфинкторы знаете. :)


checkmate-maker   (2008-10-14 15:00:00) [31]


> Параметры из объекта окружения, так называемый функтор.


> Идея понятна?

Спасибо, но непонятно как связать построенную Вами ООМ c моей задачей.
Объявлять методы в одном классе, а реализовывать в его наследниках я, к счастью, умею.
Спасибо за термин "функтор"  - почитаю.


Сергей М.   (2008-10-14 14:58:00) [32]


> oxffff


Какие контракты, какие функторы ?
Ты сейчас с кем разговариваешь ?)
У человека D 7, а ты ему про функторы да про сфинктеры)


oxffff   (2008-10-14 14:58:00) [33]

Могу еще предложить вариант

IGetParameterCallBack=interface
function GetParameter(idx:integer,var param):boolean;
end;

TUnyProc=function (const GetParameter:IGetParameterCallBack):integer;

function MyProc(const GetParameter:IGetParameterCallBack):integer;
var a:integer;
    b:string;
begin
if not GetParameter.GetParameter(1,a) then showmessage('No params');
if not GetParameter.GetParameter(2,b) then showmessage('No params');
....
end;


oxffff   (2008-10-14 14:51:00) [34]


> Честно говоря не пробовал но Barry использует "очень жесткое"
> при generics.Collections.defaults, а точнее


cм.
Generics.Defaults;

функция создания объекта нештатными средствами.
function MakeInstance(vtable: Pointer; sizeField: Integer): Pointer;


Сергей М.   (2008-10-14 14:50:00) [35]


> Видимо, придется пользоваться try..except


Это не обезопасит, а только усугубит последствия.
Исключение ты, возможно, и поймаешь, но при этом нет никакой гарантии, что код, вызвавший исключение, не натворил непоправимых бед в АП процесса.

Может быть, есть резон обратить взор на ole-автоматизацию и диспинтерфейсы ?


oxffff   (2008-10-14 14:47:00) [36]


> a:TGetProc<TMyProc2>;
> a:TGetProc<TMyProc3>;


> a:TGetProc<TMyProc2>;
> b:TGetProc<TMyProc3>;


oxffff   (2008-10-14 14:46:00) [37]


> checkmate-maker   (14.10.08 14:37) [14]


В таком случае при изменении контракта тебе лучше использовать другой вариант. По аналогии с анонимным методом.
Параметры из объекта окружения, так называемый функтор.

UnyCall=class
procedure UnyCall;virtual;abstract;
end;

UnyCall2=class(UnyCall)
protected
a:integer;b:string;
procedure UnyCall;virtual;abstract;
constructor (a:integer;b:string);
procedure UnyCall;override;
end;

constructor (a:integer;b:string);
begin
self.a:=a;
self.b:=b;
end;

procedure UnyCall;override;
begin
use A,b here
end;

Вызов такой.

var a:UnyCall;

a:=UnyCall2.create(1,'2')

a.unycall();
...

Идея понятна?


oxffff   (2008-10-14 14:41:00) [38]


> По сути дела в зависимости от параметра возвращает разные
> процедуры. Например если параметр = 0, то это процедура
> без параметров, если = 1, то с одним. Понимаю, что в зависимости
> от параметра следует использовать разное объявление переменной
> f, но хочется подстраховаться перед вызовом f, хочется знать,
>  на процедуру с каким числом и каких параметров воззвращен
> указатель.


Этот подход совершенно не выразителен и небезопасен.
Если возвращаемые функции известны в Compile time, то тебе нужно сделать

TGetProc<T>=function GetProc(idx:integer):T;
TMyProc2 = procedure(a0: Integer; a1:String); stdcall;
TMyProc3 = procedure(a0: Integer; a1:String;a2:String;); stdcall;

a:TGetProc<TMyProc2>;
a:TGetProc<TMyProc3>;
begin

//Сделать жесткое присваивание.
Честно говоря не пробовал но Barry использует "очень жесткое" при generics.Collections, а точнее
a:= @GetPtr
b:=@GetPtr

a(2)(1,'2')
b(3)(1,'2','3')

Надеюсь идею понял. :)


checkmate-maker   (2008-10-14 14:37:00) [39]


> А чего собственно ты боишься, коли о страховке задумался
> ?


Интерфейс процедур в библиотеке меняется чуть реже, чем заходит солнце. Сложно быть уверенным в том, что завтра у процедуры в библиотеке не добавиться/убавиться еще один параметр, измениться тип. Хочется отловить эту ситуацию.
 Пока, чувствую, самое верное из форума - это фраза:

> Возвратив pointer ты сознательно "обезличил" подпрограмму.

 Видимо, придется пользоваться try..except.


Сергей М.   (2008-10-14 14:24:00) [40]


> хочется подстраховаться перед вызовом f


А чего собственно ты боишься, коли о страховке задумался ?


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо