Внутренняя реализация Клариона

На днях, после того, как послал письмо с описанием внутренних структур File и Queue, опять решил вернуться к данной теме. Подумал — почему такие сложности с конвертацией файлов, в особенности TPS? Если для простого конвертирования файлов DAT можно легко воспользоваться старым добрым Filer`ом из поставки CPD21, то для TPS-файлов нет ничего  подобного.
А если и есть, то все они громоздкие, сложные и, что главное для нас, дорогие. Не справедливо?!
Вот и решил написать что-то подобное. И для этого пришлось уточнить формат всех тех
структур, которые описывал.

Сразу-же предупреждение тем, кто решил воспользоваться информацией из того письма, особенно Сергею Чушкину -верен формат ТОЛЬКО заголовка файла. Все остальное очень сильно изменилось с времен CDD30/CFD31! Читать далее

Некоторые наблюдения по QUEUE #2

Не так давно Сергей Чушкин спрашивал насчет паковки записей очередей в C5-C55. Тогда я ответил, что подробно еще не разбирался с очередями.

В общем, подошла и очередь очередей :)(Каламбурчик, однако!) Теперь могу сказать точно — паковка в очередях есть и она работает! Более подробно сам механизм:

При общем размере записи (без учета OVER-полей) до 127 байт (включительно) запись не пакуется.
Начиная с размера 128 байт запись пакуется по простому алгоритму:
При упаковке вся запись рассматривается как массив байтов, без различения полей и их типов. При этом все повторяющиеся байты заменяются на последовательность <длина,байт-образец>. Перед последовательностью, которую не удалось сжать таким образом, ставиться байт с установленным старшим битом. Все остальные биты этого байта используются для задания длины несжатой последовательности. При необходимости (для задания большой длины) к данному байту добавляются еще байты. Аналогично и для задания кол-ва повторений байта-образца.
Только теперь старший бит сброшен.

В общем случае, для любой очереди, в качестве управляющей информации, распределяется около 1Kb памяти. Это без учета динамических ключей и накладных расходов на каждую запись.
Накладные расходы на каждую запись составляют 28 байт.
Кстати, из этих 28 байт полезной инфы — только 12 байт!
Остальные 16 байт — инфа менеджера памяти. На каждый динамический ключ еще по 4 байта.
Для упакованных записей — еще 4 байта. Да и еще каждая запись (упакованная или нет) выравнивается на границу 8 байт. Т.е., в худшем случае — еще +7байт.
Вот такая арифметика!

Кстати, реализовано все это достаточно нетривиально.
В заголовке каждой записи есть указатель, с помощью которого, через таблицу дискрипторов, вызывается процедура для обработки данной записи. Для неупакованных и упакованных записей она разная. В общем случае, для всех записей очереди вызывается одна и та-же процедура. Но, никто ведь не мешает повесить на каждую запись свою, уникальную, процедуру обработки данной записи! Какие, однако, перспективы!

И, вообще, согласен полностью с, кажется А.Ивановым, что очереди в Кларион — это сила!
Если-бы еще найти как подменить внутреннюю процедуру сортировки на свою, тогда вообще был бы полный кайф!

Некоторые наблюдения по QUEUE

Возможно кому будут интересны некоторые выводы по работе очередей, которые (выводы) сформировались в результате небольшого «копания» в них. Все выводы относятся ТОЛЬКО к реализации очередей в версии C5bee.

Динамические ключи действительно существуют и работают.

При первом поиске (Get) по неключевому полю (полям) выполняется стандартный SORT по этому полю (полям). Результат данной виртуальной сортировки сохраняется в так называемом «динамическом ключе», который представляет собой обычный массив из указателей на физические записи очереди. Под указателем имеется ввиду НЕ номер записи в очереди а именно указатель на область памяти, где физически размещена запись. Это дает возможность не перестраивать повторно уже созданные динамические ключи при изменениях очереди, таких как Add/Put/Delete/Sort. Читать далее

Я знаю как можно работать напрямую с файловыми и QUEUE структурами

Я знаю как можно работать напрямую с файловыми и QUEUE структурами. Т.е. можно использовать их динамическое формирование/изменение/удаление.

Очередь в памяти представлена практически так-же как и описание файла.
Например, тип FILE — это указатель на область памяти, которую назовем, например, «заголовок файла». Формат этого заголовка остался практически неизменным со времен CDD30. Несколько изменились лишь типы некоторых полей и в C5 добавились несколько полей, назначение которых Читать далее

Экономия места в браузе: Full Splitter

«дизайнерский» момент 🙂

  • Автор: Still Zero
  • Дата публикации: 30.12.2005
  • Уровень: начальный

Я думаю, что зачастую, размещая элементы на окне просмотра данных, вы сталкиваетесь с ограничением размеров экрана. Существует такая вещь как splitter — разделитель, который помогает уменьшить/увеличить зону видимости листа. Как он работает можно посмотреть, например, в Проводнике Windows.

Но сегодня речь пойдет не о разделителе 🙂 … а о похожей на него вещи, я не знаю как это правильно называется — назвал Full splitter — полный разделитель. Задача, которая ставится перед этим элементом — полностью скрыть часть окна слева (или справа) от разделителя.

Full splitter реализовывается буквально несколькими строками кода.

Между областями, которые необходимо разделить положим кнопку. Установим на кнопку клавишу быстрого вызова (Key). В качестве клавиши может выступать, например, кнопка с буквой «Ё», или, что тоже, знаком «тильда». Также, напишем tip-чик на кнопке, что то вроде «Скрыть/показать области». Текст с кнопки необходимо удалить. Желательно установить другой вид курсора для кнопки.

Необходимо завести «флаговую» переменную, которая будет показывать скрыта ли часть или нет.

При нажатии на кнопку-разделитель должны выполняться следующие действия:

  • определяемся, что необходимо делать — скрывать область или показывать (по «флаговой» переменной);
  • если скрывать — скрываем все контролы левее (правее) разделителя — команда HIDE и изменяем размеры контролов правее (левее) разделителя на величину освободившегося места, также меняем положение самого разделителя — это свойства Prop:Xpos, Prop:Ypos, Prop:Width, Prop:Height;
  • если показывать, то показываем ранее скрытие контролы — команда UNHIDE, и восстанавливаем предыдущее положение контролов

Пример собран на C55H, ABC.
Я использую стандартный ABC-ресайзер (resizer). Возможно для вашего ресайзера код обновления будет несколько другим. Все действия со сплиттером я вынес в простой локальный класс. Собственно такой сплиттер был подсмотрен в EMS MS SQL manager-е SplitDemo (907)

Локальные хуки

Установка локального хука

  • Автор: Still Zero
  • Уровень знаний: advanced
  • Подразделы: нет
  • Дата публикации: 06.12.2005

Впервые прочитав о локальных хуках, я решил, что это абсолютно никчемная вещь. Есть ведь сабклассинг, его вполне достаточно. Но, все-таки дочитал до конца и попробовал в применении. Реальная вещь. Сабклассинг отдыхает 🙂

Устанавливая хук, вы указываете процедуру, которая может обрабатывать сообщения ОС. По сути — тоже что и сабклассинг. Мулька в том, что сообщения приходят в процедуру хука раньше, чем они попадут в сабклассинг. Также, можно установить хук так, чтобы в него попадали сообщения уже после того, как они «побывали» в процедуре окна.

Хуки бывают разных типов. Тип задается при установке хука.
Хук, который отлавливает те же сообщения, которые попадают в процедуру сабклассинга имеет тип WH_CALLWNDPROC.
Хук, обрабатывающий сообщения после того как они побывали в процедуре сабклассинга имеет тип WH_CALLWNDPROCRET. Читать далее

ИЗО: рисуем в памяти и в не клиентской области

О рисовании в MS Windows

  • Автор: Still Zero
  • Уровень знаний: advanced
  • Подразделы: нет
  • Дата публикации: 03.11.2005

О окнах
Окна, как возможно вам известно, состоят из двух областей: «клиентской» и «не клиентской». К «не клиентской» области относится заголовок (caption), статус-бар, фрэйм (бордюр вокруг окна), вертикальный и горизонтальный скролл-бары. Все остальное, а это «внутренности» окна — клиентская часть.
Рисование в этих областях различается. В эти области приходят разные события. Так например, при рисовании клиентской части приходит событие WM_PAINT, а не клиентской — WM_NCPAINT.
Области имеют разные хэндлы. Хэндл клиентской части — MyWindow{Prop:ClientHandle}, хэндл не клиентской — MyWindow{Prop:Handle}. Читать далее

Вызов Clarion функции из Delphi

Вызов функции на Delphi из Clarion и передача параметров

  • Автор: Evgeny Stefanenko
  • Уровень знаний: начальный/advanced
  • Подразделы: нет
  • Дата публикации: 21.10.2005

Задача: Вызвать из функции на Delphi функцию написанную на Кларе.

Создаем в Кларионе функцию с параметрами:

ClarionProcedure(LONG Param), LONG,PASCAL

Ее мы собственно из Delphi и будем вызывать…

Далее в Delphi лепим на скорую руку проект в котором описываем нашу процедуру как:

var ClarionProcedure: function(Param: Integer):Integer; stdcall;

Важно указать именно stdcall, для того что бы Delphi правильно передавала параметры в Clarion. Читать далее

Диалог выбора компьютера

Диалог выбора компьютера по аналогии с диалогом выбора папки

  • Автор: Still Zero
  • Уровень знаний: начальный
  • Подразделы: нет
  • Дата публикации: 21.10.2005

Как вы знаете, существует стандартный диалог выбора файла/папки. В Кларионе для этого используется команда FILEDIALOG. По большому счету, этой же командой можно воспользоваться для выбора компьютера в сети, но это не очень удобно, так как нет возможности сразу же встать на папку «Сетевое окружение», показываются «расшареные» ресурсы компьютеров и существует возможность выбора обычных папок. Поэтому, приложим немного усилий и пойдем другим путем.

Во-первых, существует несколько API функций для обзора сети: WNetOpenEnum, WNetEnumResource, WNetCloseEnum. Используя эти функции, можно перечислить ресурсы сети (сами сети, домены, компьютеры, «шары» и т.п.). Минус этого метода в том, что функция WNetEnumResource, которая собственно и отвечает за перечисление ресурсов, достаточно медленная. В примерах обычно показывается рекурсивный вызов этой функции, что еще более замедляет работу Читать далее