![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Переменные процедурного типа [D7, XP]
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
А чего собственно ты боишься, коли о страховке задумался ?