Я знаю как можно работать напрямую с файловыми и QUEUE структурами. Т.е. можно использовать их динамическое формирование/изменение/удаление.
Очередь в памяти представлена практически так-же как и описание файла.
Например, тип FILE — это указатель на область памяти, которую назовем, например, «заголовок файла». Формат этого заголовка остался практически неизменным со времен CDD30. Несколько изменились лишь типы некоторых полей и в C5 добавились несколько полей, назначение которых неясно:
TPointer ULONG
TPtr LIKE(TPointer) ! Указатель
TStrPtr LIKE(TPtr) ! Указатель на строку
FileGrp GROUP
FilePtr &FILE
END
FileAddress LIKE(TPtr),OVER(FileGrp) ! Адрес "заголовка файла"
FileHeader GROUP
DriverPtr LIKE(TPtr) ! указатель на точку входа драйвера файла
NamePtr LIKE(TStrPtr) ! имя файла
NameSize ULONG ! длина имени файла
DrvInitPtr LIKE(TStrPtr) ! строка инициализации драйвера
DrvInitSize ULONG ! длина строки инициализации
PasswordPtr LIKE(TStrPtr) ! пароль файла
PassSize ULONG ! длина пароля
Status BYTE ! статус файла
KeyCount BYTE ! количество ключей
MemoCount BYTE ! количество MEMO-полей
RecordSize ULONG ! размер записи (буфера записи)
FieldsDefPt LIKE(TPtr) ! описание полей записи файла
KeysDefPtr LIKE(TPtr) ! описание ключей файла
MemosDefPtr LIKE(TPtr) ! описание MEMO-полей
RecordPtr LIKE(TPtr) ! указатель на буфер (RECORD)
Reserved ULONG ! резерв (всегда = 0)
Res1 BYTE ! ???
Res2 BYTE ! ???
END
Для заполнения данной группы надо выполнить что-то типа:
FileGrp.FilePtr &= MyFile
PEEK(FileAddress,FileHeader)
Кстати, можно увидеть, что довольно легко добраться до драйвера файла и, при необходимости, легко можно его сменить по ходу программы! Только заранее надо позаботиться, что-бы нужный драйвер был прилинкован к проге. Проще всего написать файлы-пустышки для всех нужных драйверов и, при необходимости, просто вытаскивать из них готовый адрес нужного драйвера и вставлять в заголовок своего файла.
Формат описания полей, ключей, MEMO-полей так-же известен. Даю его в отдельном файле. Делал его еще для CDD30, но дальше тестов так и не пошло. В CW не проверял, но, думаю, что эти форматы не изменились.
Кстати! Сейчас пришла в голову мысль, что поле Reserved вполне может быть указателем на блок описания BLOB-полей!? По аналогии с MEMO-полями.
Так вот, насчет формата описаний. Я довольно нормально их описывал. Так что, при желании, разобраться можно. Если чего будет не понятно — пиши. Я еще помню все это, так как повозился с этим делом тогда порядочно!
Теперь, что касается очереди.
Здесь почти полная аналогия с файлами. Тип QUEUE — опять-же, просто указатель на так называемый «заголовок очереди». Для CW я его не «копал». Но не думаю, что он очень сильно изменился со времен CDD30:
QueueGrp GROUP
QueuePtr &QUEUE
END
QueueAddress LIKE(TPtr),OVER(QueueGrp) ! Адрес "заголовка очереди"
QueueHeader GROUP
RecordPtr LIKE(TPtr) ! указатель на буфер (QUEUE)
FieldsDefPt LIKE(TPtr) ! описание полей записи очереди
ControlPtr ULONG ! служебный указатель ?
RecordSize SHORT ! размер записи (буфера записи)
! в CW, возможно, ULONG
FirstRecPtr LIKE(TPtr) ! указатель на первую запись
LastRecPtr LIKE(TPtr) ! указатель на последнюю запись
! вначале оба = 0
RecsCount ULONG ! количество записей
END
Для заполнения данной группы надо выполнить что-то типа:
QueueGrp.QueuePtr &= MyQueue
PEEK(QueueAddress,QueueHeader)
Когда игрался в CDD30 с очердью, то удалось разобраться в назначении ControlPtr. Сейчас уже не помню, но он как-то связан с указателями на первую и последнюю записи (или это мне приснилось ?:)).
Формат описания полей очереди абсолютно идентичен формату описания полей файла. По крайней мере был идентичен в CDD30. Кстати, поля FirstRecPtr и LastRecPtr это, на самом деле, указатели на «заголовок записи». К сожалению, записки по очереди где-то затерялись. Поэтому не помню точно формат этого «заголовка записи». Что-то типа:
QueueRecHdr GROUP
PrevPtr LIKE(TPtr) ! указатель на предыдущую запись
NextPtr LIKE(TPtr) ! указатель на следующую запись
RecSize ULONG ! длина записи
RecPtr LIKE(TPtr) ! указатель на сами данные
! а может - наоборот?
END
Зачем здесь указан еще раз RecSize?
Дело в том, что при выделении памяти под очередную запись необходимый размер вычислялся без учета концевых пробелов строки, если она — последняя в описании записи очереди. Так было до C5. В С5 стали усекать все строки, независимо от их месторасположения в записи. И это действительно так, сам проверял недавно. Таким образом, в результате, вся текущая запись может занять буфер памяти меньше, чем указано в заголовке очереди, в поле RecordSize. А уже RecSize содержит действительный размер текущей записи.
Кстати, можно догадаться, что в C5, при выделении памяти, стали работать с полями, используя их описание из FieldsDefPtr. Чего не было в ранних версиях. Там определяли размер текущей записи просто: RecSize = Len(Clip(Queue)). Соответственно, при Get/Put, в С5 опять-же идут по полям, в отличии от предыдущих версий, где было достаточно : MoveMem(RecPtr,RecordPtr).
Исходя из этого, можно предположить, что основные операции работы с очередью (Add/Get/Put) в С5 работают медленнее чем в предыдущих версиях!?
Может кто проверит, у кого есть обе версии — C4 и C5?
В принципе, используя эту инфу, можно организовать какие-либо дополнительные функции для работы с очередью, минуя штатные функции Get/Put и прочие. Хотя — зачем?
Вот, в общем-то и все!
P.S.
Еще раз напоминаю — в приложенном файле -инфа по структуре файла, как она была в CDD30!!! (см.здесь dbdrv.zip )
Так что, как пишут в лицензиях: «Если у Вас что сломается, мы за себя не отвечаем!»
Еще есть несколько «ядреных» функций, которые можно было-бы «пощупать»:
- Cla$Addqueuekey/Cla$Addqueueskey - интересно, не правда-ли?! - Cla$SORTqueuekey/Cla$SORTqueueskey - ??? - Cla$PUTqueuekey/Cla$PUTqueueskey - ??? - Cla$POSITIONqueuekey/Cla$POSITIONqueueskey - ??? - Cla$GETqueuekey/Cla$GETqueueskey - ??? - Cla$FREEqueuekey/Cla$FREEqueueskey - ??? - Cla$NUMFIELDSqueue - довольно красноречивое название
По-моему, это — прямые функции для работы с альтернативными ключами очереди. И ключи эти, очевидно, представляют собой обычные очереди.
Есть и отдельные функции для работы с полями очереди, по аналогии с полями группы: Cla$WHOqueue/Cla$WHATqueue/Cla$WHEREqueue
Интересно, что они такого дополнительного делают, чего не делают их аналоги WHO()/WHAT()/WHERE()?
Возможно просто вытаскивают из заголовка очереди указатель на буфер очереди и уже после этого используют стандартные функции по работе с полями группы
Это так сказать для затравки!
А там, глядишь, у кого-либо зачешутся руки и этот кто-либо покопается еще во все этом. А потом еще и выложит нам результаты своих «раскопок».
И, в результате, может дойдем вместе до полного и точного описания этих «святая святых» Клариона.
Все-таки, что не говори, а реализация FILE & QUEUE (и, вероятно, еще и GROUP) — одна из основных фич Клариона, какие, собственно, и сделали его таким, каким он есть — отличным от других!
