Я знаю как можно работать напрямую с файловыми и 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) — одна из основных фич Клариона, какие, собственно, и сделали его таким, каким он есть — отличным от других!