Архивы автора: Evgeny Stefanenko


Классы #3

bdr>  Прочитал твои два послания. Спасибо за информацию.
bdr>  У меня к тебе два вопроса, если есть время.
bdr>  1. Чем все таки лучше и правильно ли использовать
bdr>  Init       PROCEDURE(*GROUP _objB)
bdr>   или как приводил Андрей передавать адрес класса в STRING
bdr>   и почему неиспользовать
bdr>   Init       PROCEDURE(ClassB _objB)

Как внес поправку Андрей — передавать адрес через строку удобнее при запуске нового потока. Так как только строки возможно передавать в качестве параметров. При обычном вызове — лучше передавать через группу, т.к. — это «родной» формат для класса. Использовать в качестве параметра класс — тоже правильно. Другое дело, что при таком описании ты не сможешь в эту процедуру передать другой класс. А при передаче через строку или группу можно передавать любые классы.

bdr>  2.Второй вопрос несколько на другую тему, но о классах
bdr>  Описаны 3 типа класса: класс А; и В и С порожденные от А
bdr>  В некую процедуру(это может быть и метод вообще другого класса)
bdr>  в качестве параметра передаются класс типа В или С
bdr>   ( Procedure(ClassA CurrentClass)). Как в этой процедуре определить
bdr>  что передан класс типа В или класс типа С, неспользуя дополнительных
bdr> параметров.  В DELPHY для этого есть AS.

Два способа:

я иногда завожу в классах строковую переменную, в которую при инициализации записываю название типа класса.

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

Есть, правда, еще один способ. Посложнее. Класс передается в процедуру по адресу его буфера. Первым лонгом в этом буфере идет адрес таблицы виртуальных методов. Вот уже он — разный для разных классов. Он назначается на этапе компиляции. Так что, в принципе, в начале программы можно составить некую таблицу этих адресов VMT для разных классов и уже по ней идентифицировать классы. Кстати, если у класса нет виртуальных методов или вообще нет методов — все равно этот параметр есть. Он используется RTL-библиотекой для получения полной инфы о структуре класса. Эта инфа записана непосредственно ПЕРЕД тем адресом, на который указывает адрес VMT.

Классы #2

bdr> <.. не с потолка же я взял этот механизм ..
bdr>  А можно поинтересовать как ты к этому пришел.
bdr>  Мне лично не понятно как вообще компилятор это пропускает.
bdr>  Ведь в STRING может и не лежать адрес класса, а приведение к указателю
bdr> класса неизвестно чего

А это уже твои проблемы! Я когда-то уже писал, в Кларионе можно сделать очень много разных нестандартных вещей. Практически как в С. Но и ответственность за неправильное их использование ложиться уже на программиста.

bdr>  должно отлавливаться компилятором.
bdr>  Это что глюк или «расширение» возможностей клариона.

Это — обычное поведение компилятора. Конструкцию типа:

Ref &= (Var)

компилятор воспринимает как приведение к лонгу и уже этот лонг принимает за обычный адрес.

bdr>  Сразу возникает вопрос, а чего еще можно вытворять в кларионе подобного.
bdr> Александр Бирюков

А чего надо?:)

Классы

bdr>  Если первый пример мне понятен, то со вторым:
bdr> <Ещё, Если Вы хотите загружать динамически какие то библиотеки то не
bdr> <используёте LoalLibrary, а используйте Cla$LoadLibrary, прототипы те-же

Угу. Только чуточку по другому:

  MAP
    LoadLib(LONG _LibNameAddr),LONG,NAME('Clw$LoadLibrary')
  END

_LibNameAddr — адрес строки CSTRING с именем библиотеки.

bdr> А можно хоть небольшой комментарий.
bdr> Что это дает?
bdr> Александр Бирюков

По большому счету, эта — простая надстройка над API-шной LoadLibrary:

  • сохраняет регистры CX,DX
  • забрасывает адрес строки из AX в стек
  • вызывает LoadLibraryA
  • востанавливает DX,CX
  • возвращает AX

По своему опыту общения с Кларионом на низком уровне могу сказать, что Кларион ОЧЕНЬ чувствителен к регистрам. Поэтому, когда идет вызов ЛЮБОЙ процедуры, компилятор предполагает, что после возврата из этой процедуры все основные регистры (BX,CX,DX,SI,DI) имеют тоже значение, что и до вызова. Не «закладывается» компилятор только на AX, и то, только для функций, которые возвращают результат через AX.

Я таким образом уже несколько раз «влетал» со своими asm-процедурами. Пока не стал сохранять/восстанавливать регистры, постоянно «лезли» какие-то левые глюки.  Удалось «вычислить» только после кропотливого анализа сбойного участка с откатом назад, до места-источника проблем.

В принципе, компилятор должен учитывать, что процедуры с атрибутами C или PASCAL могут иметь другое поведение по отношению к регистрам. Но, очевидно, иногда где-то он все-таки «прокалывается» или вообще не принимает этого в расчет.

Так что, если по хорошему, то стоит для всех используемых API-шных процедур писать кларионовскую процедуру-надстройку, в которой будет только вызов API-шной процедуры. При генерации Кларионовской процедуры компилятор сам анализирует, какие используются в процедуре регистры и их сохраняет/восстанавливает.

Over-field in List-queue

Que     QUEUE
Name      STRING(40)
Key       STRING(10),OVER(Name)
Desc      STRING(100)
Price     DECIMAL(11,2)
        END

?List{PROP:Use} = Que

  1. List not «sees» OVER-field QUE.Key
  2. List considers, that the field Desc has number 2, and field Price has number 3.
  3. ?List{PROPLIST:FieldNo,2} return 2.    ! column for Desc field Who(Que,2) return «Key».
  4. Sort(Que,+Que:Desc); Sort(Que,-Que:Desc)
  5. We delete all records from the list. Sometimes we obtain GPF.
  6. End program or procedure — Always we obtain GPF.

CallBack Procedure

VS> Что-то я в силу несколько усеченных познаний в буржуйском языке плохо представляю  из Help’а, как работать с CALLBACK(entity, FileCallBackInterface, [flag]). Если у кого-то есть готовый пример, а еще лучше — пример под шаблоны Вадима Синявского, буду весьма признателен.

Так а в чем проблема-то? В доке кажется нормально все описано. Да и пример даже есть. Тоже нормальный.

Ну, на всякий случай:

Все знают, что работа в Кларион с файлами организована через драйвера. Драйвер — это обычная процедура, которая принимает все обращения к файлу. Эта процедура является как бы диспетчером, когда для выполнения определенной операции управление передается уже конкретной подпрограмме, входящей в драйверный модуль вместе с процедурой-диспетчером. Возможно не все знают, но работа с View так-же организована через процедуру-драйвер VIEWDRIVER, входящей в рантайм — библиотеку Клариона. Читать далее

Так что, Size() — это обычная рантаймовская ф-ия?

NT> Так что, Size() — это обычная рантаймовская ф-ия? Я полагал, что эта ф-ия NT> вычисляется компилятором:
NT> «SIZE Supplies the amount of memory used for storage. NT> variable The label of a PREVIOUSLY DECLARED variable. NT> […] NT> SIZE directs the COMPILER to supply …»

Все правильно — Size() это не рантаймовская функция, но компилятор обрабатывает ее интеллектуально а не просто вычисляет на этапе компиляции. Если мы просим дать нам размер переданной в процедуру строки, то компилятор в качестве результата Size() подставляет значение внутренней переменной, в которой хранится длина переданной в процедуру строки. То-же касается и рефералов на строки/группы/очереди/классы — компилятор генерит код, который «вытаскивает» из этих рефералов нужное значение.

Так что, в доке — немного неполная инфа по Size(). И можно, с некоторой натяжкой, считать, что Size() — это рантаймовская функция в виде online-кода.

Вместо процедур клары PEEK, POKE можно использовать…

АА> !  Вместо процедур клары PEEK, POKE
АА> !  можно использовать
АА> !
АА> !  MoveMemory(Long adrto,long adrFrom,long
АА> ! sz),bool,proc,pascal,name('RtlMoveMemory')
АА> !
АА> !  1-параметр адрес куда записывается
АА> !  2-параметр адрес куда пишется
АА> !  3-размер копируемых данных
АА> !
АА> !  Александр Бирюков
АА> Очень интересно! А ты не пробовал посмотреть эту ф-ю на ассемблерном уровне?
АА> Это одна asm-команда копирования строки (через запись адресов и длины в
АА> регистры) или они побайтно копируют? Для меня это очень актуально (надо
АА> поднять скорость приложения, а оно по большей части именно память с места на
АА> место копирует).
АА> И как у этой ф-ии с совместимостью между версиями? И как она представлена в
АА> разных режимах линковки (Local/Stand..)?

Делать замену операторов PEEK()/POKE() имеет смысл только для структур или массивов. Так как для стандартных типов BYTE-LONG, компилятор заменяет эти операторы на одну-две асм-инструкции.

И если уж делать их замену, то лучше вместо предложенной API-шной функции Читать далее

Как узнать адрес начала и конца КОДА процедуры?

Адрес начала — Address(Proc).
Адрес конца — сомневаюсь. Если в модуле, где сидит данная прога есть инфа о длине проги, то тогда понятно, как определить адрес конца (проги). Хотя, сомневаюсь, что такое кто-нибудь делает.

Правда, исследуя недра Клариона, могу сказать, что в подавляющем большинстве процедур, есть только ОДИН выход через RET NEAR. И обычно всегда — в конце кода процедуры. По крайней мере, я иных не встречал. Хотя допускаю их наличие.
Так что, можно просканировать память с адреса начала процедуры и до нахождения кода оператора RET NEAR. Это и будет, с большой вероятностью, адрес конца кода данной процедуры.
Кстати, все процедуры в Кларионе завершаются именно оператором RET NEAR xx. Даже процедуры из внешних DLL-библиотек. Для вызова таких процедур Кларион эмулирует «дальний» вызов с помощью дополнительной локальной процедуры с одним оператором JMP _DllProc. Читать далее

Перебираю поля группы циклом. Как мне отличить корректные значения AnyVar от некорректных?

YF> Перебираю поля группы циклом.Для каждого поля
YF>     AnyVar &= What(Group,FiedlNo)
YF> Как мне отличить корректные значения AnyVar от некорректных?
YF> Дело в том, что если поле имеет совсем неподходящий тип
YF> (массив или ссылка), присваивание всё равно срабатывает,
YF> но Any-переменная ни к чему не пригодна.
YF> Вопрос, скорее всего, к Олегу Руденко….

Когда поле описано как ссылка, то What() и вернет значение этой ссылки. Значение ИМЕННО самой ссылки, а не переменной, на которую указывает эта ссылка! Дело в том, что все ссылки в группе описаны одним общим типом REFERENCE(1Fh). Отличаются они только размером, который также передается в ANY. Если известен тип ссылки (тогда зачем What()?:)), то довольно легко получить и значение переменной, на которую Читать далее

BLOB

Олег А. Руденко

Hello, Robert.

If you are not afraid to use undocumentary possibilities of the language, then look in an attach. I have corrected your example slightly. Now it works how you wanted. My corrections are marked as «Corrections by Oleg A. Rudenko».

Briefly I shall explain:

The reference on BLOB represents group of two fields:

BLOBRef        GROUP
ParentFile       &FILE
BlobNo            SHORT
               END

This feature has allowed to realize your idea! Читать далее