Разное - ответы на часто задаваемые вопросы по CfW


Где найти документацию по CfW на русском языке ?

Ответ: Документации для Clarion 5 на русском пока нет, на Clarion 4: http://www.clarion.ruhttp://clarab.webjump.com/, http://www.pvrr.ru/~rinat/i/default.htm


Конвеpтоp досовских *.dct под Clarion5

Вопрос: Hекотоpые программки под досю хотелось бы переписать на 5 клаpе. Может имеется в пpиpоде что-либо сабжа, что бы использовались старые базы из программ под досю?  В 3 клаpе под досю есть такая функция как импорт. Тут я ничего такого не нахожу.

Ответ 1:
Я в свое время тоже хотел так сделать. Пробовал в CW 1.5, CW 2, CW 4...
Обычный open dictionary на старый dct - и он по идее должен конвертнуться. Только не надо забывать о необходимости наличия Btrieve.

Однако все мои dct в процессе загрузки вызывали падение всего CW по GPF. Кажется, только CW 1.5 не падал, но уже точно не помню. 2 и 4 падали точно. Причнину я за TopSpeed искать не хотел, сделал попроще. Взял исходник, сгенеренный CFD, и ручками переделал его на TXD, затем подгрузил.

Попутно избежал проблем с конвертацией OEM -> ANSI, о которой буржуи как всегда "забыли" (в 1.5 по крайней мере).

Отвечал Petr Korotkov  31.05.2000

Ответ 2:
Досовские app и dct можно просто открыть под виндами. Только:
1) нужно открывать их копии, иначе в дос не вернешься;
2) русские комментарии будут "крякозябрами". Их можно конвертировать перетаскивая через txa, txd.

Отвечал Nick Tsigouro  31.05.2000

Ответ 3:
Частенько этим занимаюсь:  dct просто открываю под виндами .
В 5ке все перетаскивается корректно, и перекодируется из OEM в ANSI само. Нужно только что-бы Btrieve был (я использую комплект от cw2). Заодно всплывают ошибки в dct.
А в обратную сторону через txd, но перекодирую из ANSI в OEM сам (т.е. txd открываю как текст ANSI и перекачиваю в текст OEM)

Отвечал Vladimir Degtyarenko  31.05.2000


Как поймать мышь

Вопрос:  Хочется вот ловить момент нажатия кнопки мыши в определенной области окна - координаты-то я, наверно, через mousex, mousey поймаю, а вот как поймать сам момент нажатия на левую кнопку мыши ?

Ответ:
Нужно поставить в окне control типа region и на его событие accepted повесить свою обработку мыши.

Отвечал  Andrew Korolev  31.05.2000


Как вызвать программу e-mail ?

Вопрос:
Как можно вызвать по щелчку в окне на e-mail адресе текущую почтовую программу для создания сообщения по этому адресу. Вызов www ссылки выполняется через ShellExecute Windows API.  Может есть аналогичный способ вызова e-mail ?

Ответ1:
Именно. Вызывай "mailto:your@mail.address"

Отвечал Serge Aksenov   Сентября 05, 1998      ICQ UIN: 1627378

Ответ 2:
Пример ShellExecute для отправки Mail:

LOC:Handle = Window{PROP:Handle} ! USHORT
LOC:Op = 'open' ! CSTRING(20)
LOC:File = CLIP('mailto:support@posmaster.ru?Subject=About programm version 3.20') ! CSTRING(256)
LOC:Path = PATH() ! CSTRING(256)
LOC:Param = '' ! CSTRING(256)
LOC:Show = 1 ! SHORT
LOC:RetHandle = ShellExecute(LOC:Handle,LOC:Op,LOC:File,LOC:Param,LOC:Path,LOC:Show)
Best Regards

Отвечал: Dmitry Boulatov eurosoft@mail.ru  master@cassa.ru  master@posmaster.ru 
ICQ 14510907 http://taro.da.ru  http://www.cassa.ru  http://www.posmaster.ru


Локатор по динамическому индексу ?

Вопрос:
Не знает ли кто, subj - возможно ли это и как (надоело лепить ключи и перетапливать работающие файлы) !?

Ответ:
Одно время активно использовал динамические ключи. Делал и локатор и прочий поиск. Но только "ручками" - просто не стал разбираться с возможностями шаблонов. В последнее время вместо динамического индекса использую QUEUE. Масса преимуществ как в скорости работы с ними,так и по гибкости в части сортировки, поиска, фильтрации. Некоторые обычно выдвигают довод - неудобно работать с большими файлами. Не верно! Очень удобно - намного удобней и быстрей, чем при использовании того-же динамического ключа. И не надо кивать на недостаток оперативки на клиентских компах - QUEUE тем и хороша, что отлично справляется со свопингом больших объемов на винт.

Для примера - некоторые параметры из реальной задачи :
- в файле 20000 записей размером ~500байт (общ.размер ~11Mb)
- загрузка всех записей в QUEUE занимает ~40сек (честное слово !) после загрузки QUEUE занимает ~15Mb.- сортировка по нескольким полям (в том числе и строковым) <2сек.
- поиск по неключевым полям <10сек; искал последнюю запись в таблице, т.е. - пробегал все 20000 записей; поиск проводился по 5 строковым полям с использованием INSTRING().
- фильтрация по аналогичным поиску параметрам <15сек.

P.S. При больших файлах в QUEUE не обязательно заливать целиком все поля записи - достаточно брать только нужные поля.
И еще - строки в QUEUE обрезаются (отсекаются пробелы). Опять же - экономия памяти и ускорение обработки.

Отвечал Олег Руденко   Октября 05, 1998      Oleg_Rudenko@chat.ru


Надпись на кнопке в несколько строк

Вопрос: Как можно сделать в CW2 надпись на кнопке в несколько строк?

Ответ: С вертикальной чертой только в DOS-версии, а CW необходимо наличие иконки (хотя бы пустой)

Отвечал Leonid Martjushow   Января 15, 1999


Как работать с динамическими бибилиотеками?

Вопрос:
Каковы общие правила работы с динамическими библиотеками?

Ответ:
ОБЩИЕ ЗАМЕЧАHИЯ
Обычная практика по работе с динамическими библиотеками в Кларионе такова: на этапе проектирования программист "подвязывает" к проекту DLL-библиотеку и объявляет нужные процедуры, содержащиеся в ней, с атрибутом EXTERNAL. В момент запуска приложения загружается также и экземпляр библиотеки (если он уже не загружен другим приложением).
В Windows предусмотрена и другая возможность обращения к DLL -- в ходе выполнения программы. DLL, которая нигде не была заранее объявлена, загружается в память функцией APILoadLibrary(), затем выполняется нужная функция, после чего, когда библиотека уже больше не нужна, она выгружается командой FreeLibrary().
У второго подхода есть то преимущество, что он позволяет экономить ресурсы системы. Если в приложении имеется ряд функций, обращение к которым происходит раз за сессию, а то и реже (скажем, выбор пользователем неких опций), то спрашивается: какого лешего им обременять оперативную память все время? В большом проекте таких функций может бытьнесколько десятков. Кроме того, бывают случаи, когда загрузка библиотеки в ходе выполнения абсолютно _необходима_ .

ПРИМЕР ЗАДАЧИ, КОГДА RUNTIME-ЗАГРУЗКА HЕОБХОДИМА
Один из таких случаев -- определение свободного пространства на диске. В API для этого предусмотрена функция GetDiskFreeSpace(). Однако, в документации сказано, что она некорректно работает с стройствами, чей размер превышает 2Gb. Чтобы исправить положение, в версиях Windows начиная с OSR2 (1997г) была введена альтернативная функция: GetDiskFreeSpaceEx(), которая работает правильно. (Она также присутствует в NT4.0). Если программист не знает заранее, какой релиз Windows установлен у пользователя, он не может полагаться на GetDiskFreeSpaceEx() и подвязывать ее к проекту на этапе разработки. Выход в этой ситуации: написать процедуру, которая проверяет версию Windows и в случае, если она равна или выше OSR2, загрузить и выполнить GetDiskFreeSpaceEx(). В противном случае -- либо воспользоваться другим методом, либо отказаться от проверки вообще. Версия проверяется при помощи GetVersionEx(). Можно обойтись и без проверки версии --достаточно _попытаться_ обратиться к процедуре. Если попытка окажется неудачной -- значит процедуры нет в Kernel32.

СРЕДСТВА WINDOWS-API
Сам по себе процесс загрузки DLL и поиска нужной процедуры в Windows API достаточно прост:
1) Загружается библиотека. В случае успеха результат -- переменная hLibrary -- превышает 32 (десятичное).
   hLibrary = LoadLibrary(имя_файла)
2) Определяется адрес процедуры.
   Addr = GetProcAddress(hLibrary, имя_процедуры)
3) Процедура запускается (тут все целиком зависит от языка программирования).
4) Библиотека выгружается: FreeLibrary(hLibrary)

ПРОБЛЕМЫ С КЛАРИОHОМ
В кларионовский исходник нетрудно внедрить все перечисленные пункты за исключением (3). Hа C или Паскале это делается элементарно: функция объявляется как тип, затем объявляется переменная этого типа, адрес библиотечной функции (полученный на 2 этапе) назначается адресом функции-переменной и дело с концом. Вот пример на Паскале:

Type
   TMyFunction = procedure(список_параметров);
Var
   MyFunction: TMyFunction;
Затем, в теле программы:
   @MyFunction:= GetProcAddress(ссылка_на_библиотеку,имя_библиотечной_функции);        MyFunction(список_параметров);

В Кларионе подобный механизм, AFAIK, отсутствует. Во всяко мслучае, мои эксперименты с ADDRESS(), CALL() и ссылками ничем, кроме "Syntax Error" не увенчались.

ИHТЕРФЕЙС КЛАРИОH-СИ
В раздел MAP головного кларионовского модуля было включено следующее:

MODULE('WINDOWS')
GetProcAddress(HINSTANCE,*LPCSTR),LONG,PASCAL,RAW    FreeLibrary(HINSTANCE),BOOL,PASCAL,PROC GetDriveType(*LPCSTR),UNSIGNED,PASCAL,RAW,NAME('GetDriveTypeA') GetDiskFreeSpace(*LPCSTR,*DWORD,*DWORD,*DWORD,*DWORD),BOOL,PASCAL,RAW,PROC,NAME('GetDiskFreeSpaceA') LoadLibrary(*LPCSTR),HINSTANCE,PASCAL,RAW,NAME('LoadLibraryA') END MODULE('DISKINF.C') GetDiskSpace(*CSTRING,*ULONG,*ULONG),BOOL,PASCAL,RAW,PROC, | NAME('_GetSpaceEx')
END

MODULE('DISKINF.C')
   GetDiskSpace(*CSTRING,*ULONG,*ULONG),BOOL,PASCAL,RAW,PROC, | NAME('_GetSpaceEx')
END

ПРИМЕЧАHИЯ
Проект компилировался для 32-битных Windows. Hекоторые из API-функций, которые здесь используются, отсутствуют в Win3.1. Функции LoadLibrary(), GetProcAddress(), FreeLibrary() присутствуют ив 16-битных Windows, так что загружать библиотеки в ходе выполнения можно в любой версии.

Предполагается, что вместе с Кларионом установлен компилятор C/C++ (это определяется в начале инсталляции).
Если типы, определенные в C-модуле хранятся в отдельном файле с расширением .h и включены директирой #include("имя_файла.h"), то в red-файле Клариона следует определить пути поиска для .h
Я не являюсь знатоком языка C.  Hаверняка, многое в представленном C-модуле можно было бы сделать изящнее. Лично мне было важно добиться результата. Вопросы, замечания и исправления присылайте.

МОДУЛЬ TOPSPEED C
В конце концов, мне надоело доить быка и я воспользовался предоставленной TopSpeed возможностью включать в кларионовские проекты исходники, написанные на C. К сожалению, header-ы для C к комплекту не прилагаются, так что все определения пришлось писать на свой страх и риск. Вот исходник, который был назван DiskInf.c и включен в разделпроекта "External Source files".

... прилагается большой исходник


Глобальный alert для всего приложения

А не знает ли кто часом, как бы сделать глобальный "Alert Key", для всей апликухи? Т.е. что бы при нажатии определенной комбинации клавиш в любом месте проги выполнялись определенные действия?

Ответ:
А на IDLE повесить?

Владимир Смелик


Проверка существования файла

Подскажите как проверить есть файл или нет.   Делаю просто open(file) соотвественно получаю сообшение об ошибке и программа кирдык а хотелось бы просто месагу на экран.

Ответ:
Есть функция из CLib:
Access(*cstring,short),short,raw,name('_access')
Первый параметр - путь.
Второй параметр:
Value ¦ Description
------+-------------------------------------
06 ¦ Check for read and write permission
04 ¦ Check for read permission
02 ¦ Check for write permission
01 ¦ Execute (ignored)
00 ¦ Check for existence of file
^^^^- то что тебе надо.
--
Alexander Шевченко


Проверка пароля пользователя

Я разрабатываю систему доступа к базам данных. И мне возник вопрос: как заставить юзверя ввести ЮНИКС-подобный пароль. Ну, типо чтобы и цыферки и маленькие да большие буковки были?
Это, чтобы не был логин и пароль "маша" :о)=
Короче, надо кодик-вставку, чтобы возвращал мне TRUE:

if  [цыфра+UPCASE+lowcase] then
    message('Password OK')
else
    message('Password is windows-like :o)');
end

То есть, как узнать мне наличие цыфры, большой буквы и маленькой буквы? Или просто генерить самим пароль?
Если генерить, то может тогда кто-нить кинуть сюда кодик как енто зделать, а то я с символами что-то призабыл как оперировать.

Ответ:
Наверное, так:
LOOP i# = 1 TO LEN(PaswordString)
    IF ISUPPER PasswordString[i#] THEN U#+=1.
    IF ISLOWER PasswordString[i#] THEN L#+=1.
    IF INSTRING(PasswordString[i#],'0123456789',1,1)    THEN D#+=1.
END

IF (U#=0 OR L#=0 OR D#=0)
MESSAGE('Несоблюдение принципов','Ошибка')
END

Игорь Смирнов


Ошибка создания контрола

При вызове ф-ии CREATE(100,create:entry) выдается сообщение "Unable to create control (system is Modal)" хотя для окна атрибута Modal у окна нет?

Ответ:
В Clarion есть такая переменная System, а у нее свойство PROP:Threading. Так вот, если она равна 1 - создавайте любой элемент управления, равна 0 - извините, SDI-программа не даст Вам этого сделать.
Так что решение вопроса заключается в правильной устанвке PROP:Threading.
Шелег Павел.


Номер недели с начала года

Есть ли стандартная функция в кларе по выводу номера недели с начала года в зависимости от даты (от 1 до 51/52).

Ответ:
INT((CurrentDate - (date(01,01,year(CurrentDate)) + choose(date(01,01,year(CurrentDate)) % 7, 1,0,6,5,4,3,2)) / 7)

Должно получится "целых недель с начала года".
Если первая неделя не начинается с понедельника (т.е. неполная), то она
отбрасывается. Хотя это и не корректно, я так думаю.
За корректностью дат ну уж следи сам...

Сергей  chusha@mailru.com

Ответ 2:
ОК, спасибо попробовал.
Почти получилось. Пришлось внести некоторые коррективы:
if choose(date(01,01,year(TODAY())) % 7, 1,0,6,5,4,3,2)>0;
  beg# = 1;
else
  beg#=0. ! Добавляем неполную 1-ю неделю
if TODAY()%7=1;
  now# = 1;
else
  now#=0
.  ! Добавляемм еще и ТЕКУЩУЮ неделю (она иначе уходит в дробь)

locweek=INT((TODAY() - (date(01,01,year(TODAY())) + choose(date(01,01,year(TODAY())) % 7, 1,0,6,5,4,3,2))) |
/ 7)+1 + now# + beg#   ! А теперь все суммируем.

С уважением, Максим Рунушкин (maxrun@admiral.ru)


Как узнать программа уже запущена или нет?

Ответ 1:
Я сделал через вызов FindWindow() из WinAPI:
!В глобальной MAP - структуре (или в winapi.clw)
MODULE('Windows.DLL')
     COMPILE('***',_WIDTH32_)
        FindWindow(LONG,LONG),UNSIGNED,PASCAL,RAW,NAME('FindWindowA')
    ***
END

!Глобальные данные
ClaWinClassName CSTRING('ClaWin8388608Class1')  !это значение определил
экспериметальным путем (вызвал GetClassName()).  Всегда имя класса такое аль
нет - вопрос к гуру из Арсиса!
MyAppWindowName CSTRING('My App')  !это надпись в заголовке окна, а не имя
APP-файла!

!Перед вызовом главной процедуры программы
HNDLR#=FindWindow(address(LMClassName),address(LMWindowName))
IF HNDLR#
  message('My App уже запущена!')
halt(0)
.

Если кто знает, как это можно сделать красивее - ВЛИВАЙТЕСЬ!!!
Mark Ivanov  mailto: ivma@ukrpost.net

Ответ 2:
Что касается предотвращения повторного запуска - вот простой и изящный способ:
в ThisWindow.Init после открытия основного окна.

        If DDEClient('MyProgram','Started')
            Return(Level:Fatal)
        Else 
            If DDEServer('MyProgram','Started'). 
        End 


 Может потребоваться добавить Include('DDE.clw') в Program map .
 
С уважением, Юрий Философов


Как заставить MEMO - поле принять текст из clipboard?

Ответ:
Имеется в виду, видимо, поле Text. А в чём, собственно, проблема? Сколько раз вставлял...   Поскольку формулировка проблемы не совсем ясна, рассмотрим разные варианты.

1. Свойство Prop:Selstart указывает, где стоит курсор в текстовом поле (если он там стоит). Тогда никто не мешает исполнить что-то типа

   Update(?MemoField)
   MemoField=Sub(MemoField,1,?Memofield{Prop:SelStart}) & Clipboard() & |
        Sub(MemoField,?Memofield{Prop:SelStart+1},.....)
   Display(?Memofield)

2. Вставка Clipboard может не получиться, если поле Text находится в режиме Overwrite. Установи Insert.

3. Вставка Clipboard может не сработать, если текстовое поле не имеет вертикального скроллбара - просто некуда вытеснить нижнюю часть.

4. Простой способ вставить данные из ClipBoard в поле Text

      Select(?MemoField)
      PressKey(CtrlV)

С уважением, Юрий Философов


Цикл по всем Buttons

В проге есть настройка делать кнопки в окнах FLAT или нет.  Сейчас в программе в начале работы какого-нить browse все эти кнопки перебираются в "лоб" по именам.
Можно ли сделать цикл и перебрать в нем все BUTTON объекты окна?

Ответ:

Можно. Если только в окне, не включая тулбар, то:

    LOOP I#=FIRSTFIELD() TO LASTFIELD()
       IF I#{PROP:Type} = CREATE:Button
         !делаешь чего-нить
       END
    END


ежели надобно прошерстить все контролы (и на тулбаре тож), то несколько хитрее:

    LOOP
      I# = 0{PROP:NextField,I#}
      IF I#
        IF I#{PROP:Type} = CREATE:Button
          !делаешь чего-нить
        END
      ELSE
        BREAK
      END
    END

С уважением, Новиков Антон  anfront@chat.ru


Прототип для функции, чтоб можно было запускать с разным количеством аргументов и разными типами аргументов?

Ответ:

MAP
  MyProc1(<?>,<?>,<?>,<?> и т.д.) - передача по значению
  MyProc2(<*?>,<*?>,<*?>,<*?> и т.д.) - передача по адресу
END

Олег А. Руденко.   Oleg_Rudenko@chat.ru

------------------------

Ответ 2:

Вот вся комбинация:
<параметр> - параметр, который можно опустить
*параметр - параметр по адресу
? - параметр произвольного типа (ну не совсем произвольного, а BYTE, SHORT,
USHORT, LONG, ULONG, SREAL, REAL, BFLOAT4, BFLOAT8, DECIMAL, PDECIMAL, DATE,
TIME, STRING, PSTRING, CSTRING, GROUP (трактуется как STRING).

Таким образом, тебе нужно что-то вроде:

MyFunction(<?>,<?>, ... <?>)

Обрати внимание, что в прототипе тебе нужно описать максимально возможное
число параметров функции.

С уважением, Илья Пащенко.


Как можно сделать всплывающую подсказку (TIP) в несколько строк?

Ответ:
Window $ ?control{PROP:Tip} = 'Строка1<13,10>Строка 2<13,10>Строка 3'

Andrew Myalin    andrew@arsis.ru


Как данные в Excel экспортировать через OLE

Ответ 1:
Если пытаться втюхивать по одному числу то и через OLE тоже тормозно, но если сделать передачу через clipboard, то очень даже шустро. Это один из простых способов:

Cole long
Cole = create(0, create:ole)
Cole{prop:create} = 'Excel.Sheet'
Cole{'Application.Visible'} = true
IN_Line = 1
IN_Column = 1
Так в конкретное поле - Cole{'ActiveSheet.Cells('& IN_Line &','& IN_Column &').value'} = IN_Value
Так назначить формат колонке - Cole{'ActiveSheet.Columns('& IN_Column &').NumberFormat'} = '# ##0'
Так вставить из clipboard - Cole{'ActiveSheet.Cells('& IN_Line &','& IN_Column &').PasteSpecial Operation:=xlPasteSpecialOperationAdd'}
DESTROY(Cole)

Vadim, Ё-MAIL: vadim@mail.esoo.ru

Ответ 2:
Я не помню, кто предлагал в своё время, но идея была неплоха - вывести
HTML-таблицу с расширением XLS и открыть по ShellExecute.

С уважением, Юрий Философов


Как узнать координаты контрола в пикселях

Ответ:
1. Положение окна легко определить через 0{Prop:Xpos} и 0{Prop:Ypos}
2. Размеры рабочих областей в пикселах возвращает функция WinAPI GetSystemMetrics (см. MSDN)

С уважением, Юрий Философов, e-Mail: дом: yufil@renet.com.ru  служ: yufil@tacis-dipol.ru


Управление элементами меню Frame из дочернего окна

Ответ 1:
Если необходимо из дочернего окна управлять HIDE / UNHIDE элементов меню попробуй сделать так:

1. Опиши пользовательское событие с кодом больше 400h
2. Опиши во Frame обработку этого события и включи туда HIDE / UNHIDE
3. В дочернем окне в нужном месте пошли событие не связанное с полем POST(твое событие, процесс), где процесс-номер процесса Frame (вообще-то он должен быть равен 1) Если нужно в коде сообщи.

Юра. george@airkaz.com

Ответ 2:
Дык, так-то оно так, но Frame может и не торопиться исполнить Post - в неактивных окнах Accept не работает или, по крайней мере, работает не всегда. Таки придётся включить таймер. А тогда и Post не нужен - бери глобальную переменную и управляй.

Юрий Философов
Корпорация "Диполь", Саратов
E-mail yufil@tacis-dipol.ru (служ)

Ответ 3:
- Делаешь глобальную переменную qqq типа WINDOW
- В USE переменной своей менюшки добавляешь через запятую её номер (например ?MenuItem,11), где 11 это номер.
- в эмбеде фрейма "после того как окно открыто" вставляешь:
  qqq&=appframe (где appframe это label frame'а)
- после этого в любом месте приложения можешь делать:
  SETTARGET(qqq)
  qqq$11{PROP:Disable}=1   ! для Дисейбл, 0 - для Энейбл
  DISPLAY()
  SETTARGET() 

Я это делаю при открытии (закрытии) окон связанных с менюшкой , хотя правильней наверное было бы после того как менюшка Accepted. .

Alexander Шевченко,  mailto: shevchik@net.zt.ua 


Как подключить библиотеку в исходных текстах

Ответ:

Итак, самый простой вариант:

- файл с текстами процедур, *.clw
- файл обьявлений этих процедур для MAP-а, *.inc
(расширение может быть любое)
- при необходимости, файл с константами, типами и переменными, которые должны быть доступны в основном приложении при вызове некоторых процедур из библиотечного модуля. Расширение может быть любое.

Иногда последние два файла обьединяют в один общий файл и внутри делают для компилятора секции директивой SECTION(). А в приложение включают не просто как INCLUDE('MyLib.inc'), а с указанием секции:

INCLUDE('MyLib.inc','Equates_and_Data')
MAP
INCLUDE('MyLib.inc','Map')
END

Итак, пример такой библиотеки:
--------------------------------------------
Файл MyLib.inc

MODULE('MyLib.clw')
MaxNum(? _Num1,? _Num2),?
END
--------------------------------------------
Файл MyLib.clw

MEMBER

INCLUDE('EQUATES.CLW')

MAP
INCLUDE('MyLib.inc')
END

MaxNum PROCEDURE(? _Num1,? _Num2)

Code
if _Num1 => _Num2 then Return(_Num1) else Return(_Num2).
--------------------------------------------

Все, простейший библиотечный модуль готов. Теперь, его подключение:

1. Скопировать оба файла в каталог \Clarion\LibSrc.
2. В проект, в раздел "External source files" включить файл MyLib.clw.
Надо заметить, что, если данный библиотечный модуль будет использоваться в нескольких проектах, то компилится он будет только один раз, при изменении или файла MyLib.clw или MyLib.inc А уже готовый обьектник будет линковаться ко всем проектам, где он используется.
3. В проект надо включить файл MyLib.inc. Если проект в виде исходника, то просто делаем:

MAP
... ! Local procedures
INCLUDE('MyLib.inc')
END

Если проект в виде APP-ешника, то вписываем подключение в точку вставки типа "In global MAP structure". Точное название этой точки вставки зависит от типа шаблонов (Legacy, ABC) и их версии и руссификации. Но, думаю, найдешь легко.

Все!
Теперь в любом месте проекта можешь спокойно вызывать процедуры из этого библиотечного модуля. Вот только библиотечные процедуры неудобно вызвать из контролов по "Call procedure". Там уже другая песня. Но всегда можно обойти и вызывать нужные процедуры из контролов через ручной код в определенных точках вставки.

Как видишь, не сложнее чем в других языках.
Замечу, что я описал создание и подключение самого простого библиотечного модуля без создания LIB- и DLL-модулей. Такой метод довольно эффективен, когда библиотечные модули часто пополняются и изменяются. Для отладки, так-же, удобно. Сам держу несколько таких больших библиотек. Удобно.

С Уважением, Олег А. Руденко.
Oleg_Rudenko@chat.ru
Oleg_Rudenko@mail.ru


Как средствами Clarion или API в удалить пустую папку

Ответ:
Для этого можно воспользоваться функциями С-библиотеки Клариного ядра:

MAP
CreateDir(*CSTRING _DirPath),SHORT,RAW,NAME('_mkdir')
RemoveDir(*CSTRING _DirPath),SHORT,RAW,NAME('_rmdir')
END

DirPath CSTRING(250)

CODE
DirPath = 'C:\TSTDIR'
if CreateDir(DirPath) <> 0
Message('Error create dir!')
else
if RemoveDir(DirPath) <> 0
Message('Error remode dir!')
. .

Кстати, эти функции работают в обеих режимах (16- и 32-бит).

С уважением, Олег А. Руденко.
Oleg_Rudenko@chat.ru
Oleg_Rudenko@mail.ru


Как получить путь и название запущенной программы

This was originally posted on one of the newsgroups in response to a question about how to get the correct name of the running exe file from within it. This time we start in the global embes with a few prototypes. First of all you need to include a file called winequ.clw. Unfortunately this file was not included with the Clarion 4 releases, but you can find it on our ftp site. As the ftp server is not operational when this is written I'm not providing a link - I will add it when the server is up again. Now, in the "After Global Includes" embed put this line of code:

Include('winequ.clw')
In the "Inside the Global map" we need to prototype one api function:

Compile('*32*',_WIDTH32_)
Module('win32.lib')
GetModuleFileName(HINSTANCE,*LPSTR,DWORD),DWORD,PASCAL,RAW,NAME('GetModuleFileNameA')
End
*32*
Omit('*16*',_WIDTH32_)
Module('win32.lib')
GetModuleFileName(HINSTANCE, *LPSTR, SIGNED),SIGNED,PASCAL,RAW
End
*16*
Now we need to declare 3 variables in the procedure where we want to use this function. This should do fine:

Loc:Instance HINSTANCE
Loc:FileName Cstring(256)
Compile('*32*',_WIDTH32_)
Loc:FNSize DWORD
*32*
Omit('*16*',_WIDTH32_)
Loc:FNSize SIGNED
*16*
Now, all we need is to use this function:

Loc:Instance = System{PROP:AppInstance}
Loc:FileName = ''
Loc:FNSize = Size(Loc:FileName)
X# = GetModuleFileName(Loc:Instance,Loc:FileName,Loc:FNSize)

After the call, the Loc:FileName variable contains the full path and filename for the .exe file you are running.

Ответ из: Icetips 18


Как сделать цветную кнопку

Ответ 1:
Если речь о цвете фона - положи на кнопку вместо иконки цветную текстуру (например, Gif). А если о цвете текста - укажи иконку None и установи любой цвет текста.
Для завершенности образа:
http://lightning.prohosting.com/~rozalex/cgi-bin/Ultimate.cgi?action=threadlist&number=1&topic=000242-000000-051800-000003.msg&Times=365,15,15,15 
--------
С уважением, Юрий Философов, yufil@tacis-dipol.ru  

Ответ 2:
Делаешь батон Transparent, и подсовываешь под него
любой цветной контрол (Rectangle, Panel и тд) по размеру совпадающему с размерами батона.

С уважением, Новиков Антон, anfront@chat.ru

Ответ 3:
Сажаешь в окно PANEL с требуемым цветом размером с твою кнопку, а на кнопку вешаешь атрибут TRANSPARENT.  Желательно на PANEL поставить PROP:BevelOuter = -1.

Alex Timkoff,  ICQnet: #62605472, aletim@mail.ru  athome@ukrpost.net  


Как "задисаблить" все поля в окне?

Вопрос:
 
Кто знает как узнать мин.- макс ном контрола  чтобы сделать disable(min, max)  или как все поля в форме "задисаблить"

Ответ:
Disable(FirstField(),LastField())

Сергей Кондурушкин,  skondurushkin@diasoft.ru 


Как вылечить аварийное закрытие C5 при наведении курсора мыши на кнопку "закрыть"?

Ответ:
В реестре изменить переменную HKEY_CURRENT_USER\Control Panel\desktop\UserPreferencemask
Первую 16-ричную цифру байта согласно таблице:
If first is "e", use "6"
If first is "a", use "2"
If first is "c", use "4"
If first is "b", use "3"
If first is "8", use "0" (number 0)
Для Windows2000
If first is "9", use "0" (number 0)
----------------------------------------------------------------------------
To disable the ToolTips that are displayed when you move the mouse pointer over the Minimize, Maximize or Close buttons, use Registry Editor to modify the "UserPreferencemask" value in the following key:
HKEY_CURRENT_USER\Control Panel\desktop 
Make note of the value. (For example: ae 00 00 00)
Double-click the UserPreferencemask entry. Under Value Data, the cursor is in front of the first value (for example from above: ae). For the first number or letter, see below for the correct value to use in the next step (the second number/letter remain the same):
If first is "e", use "6"
If first is "a", use "2"
If first is "c", use "4"
If first is "b", use "3"
If first is "8", use "0" (number 0)
Type in the correct first number, and then type the second number/letter. The original first value is moved to the right. Press delete to remove the original value. NOTE: The original value must be deleted.
For example: "ae 00 00 00" would now be "2e 00 00 00"
Restart your computer.
NOTE: If Profiles are enabled, the "UserPreferencemask" value for the .Default user may also need to changed. The key containing this is:
HKEY_USERS\.Default\Control Panel\desktop

Serg Petrov 6.09.2000:


Как динамически создавать переменные

Ответ:
Да все так-же, через RTL Клариона!

1. Выделяем память под новую переменную. Для этого лучше воспользоваться этими процедурами:

! Выделяет память и инициализирует ее двоичными нулями
RTL::NewMem(UNSIGNED _Size),ULONG,NAME('Cla$NewMemZ')
! Выделяет память и инициализирует ее пробелами
RTL::NewStr(UNSIGNED _Size),ULONG,NAME('Cla$NewMemB')

_Size - размер выделяемой памяти, определяешь сам по типу переменной. Возвращает адрес выделенного блока памяти.

ВНИМАНИЕ!!!
Надо иметь в виду, что выделяемая память не регистрируется в RTL Клариона (напрямую берется у Виндового менеджера памяти). Поэтому эта память не будет освобождена автоматом после
завершения программы. Для ее освобождения надо использовать:

RTL::FreeMem(ULONG _Addr),NAME('_free')

_Addr - адрес блока памяти, полученный из предыдущих функций выделения памяти.

Итак - память под новую переменную есть! Теперь:

2. Промежуточный этап - создание так называемой UFO-переменной. Что-то типа оболочки вокруг блока памяти, которая содержит всю необходимую информацию о перменной. Необходимо для правильной обработки новой переменной в RTL Клариона.

Для этого воспользуемся такой вот функцией:

RTL::Mem2UfoAddr(ULONG _VarAddr,BYTE _VarType,ULONG _DecFloat=0, |
UNSIGNED _VarSize,BYTE=0),ULONG,RAW,NAME('Cla$Mem2Ufo')

_VarAddr - адрес блока памяти для новой переменной
_VarType - тип создаваемой переменной
Номера типов можно взять из INC-файла моей библиотеки DynaLib, фриварный вариант которой можно взять на: http://dynalIb.narod.ru  Например: BYTE-1, LONG-6, DECIMAL-10, STRING-18
_DecFloat - Если создаем переменную типа DECIMAL/PDECIMAL, то здесь надо задать кол-во дробных разрядов.
DECIMAL(9,2) - _DecFloat = 2
_VarSize - размер новой переменной в байтах. Для переменных типа DECIMAL/PDECIMAL он составляет ~половину от общего кол-ва цифр.
DECIMAL(9,2) - _VarSize = Int(9/2)+1 = 5
С определением размеров других типов, думаю проблем не будет? Практически все это есть в доке.

Возвращает адрес созданной UFO-переменной. Если более понятно, то возвращает значение, которое, обычно, содержится в переменных типа ANY.

Ну, как и с памятью, в конце программы эти UFO-переменные надо-бы освободить, т.к. они отъедают виндовую память. И немаленькую! Для этого используем такую функцию:

RTL::FreeUfo(ULONG _UFOAddr),RAW,NAME('Cla$FreeUfo')

_UFOAddr - адрес UFO-переменной, полученный из RTL::Mem2UfoAddr()

Можно, кстати, остановиться уже на данном этапе, если получать от данной функции не адрес UFO-переменной, а сразу понятный всем ANY. Для этого запишем эту функцию так:

RTL::Mem2Ufo(ULONG _VarAddr,BYTE _VarType,ULONG _DecFloat=0, |
UNSIGNED _VarSize,BYTE=0),*?,RAW,NAME('Cla$Mem2Ufo')

Естественно, что освобождать такие UFO-оболочки надо уже по-другому:

Var1 ANY
...
Var1 = RTL::Mem2Ufo(....) ! Создали UFO-переменную
...
Var1 &= Null ! "Убили" ее

Ну, и наконец:

3. Биндим новую переменную, чтобы с ней было удобно работать. Для этого воспользуемся еще одной RTL-функцией:

RTL::Bind(ULONG _UFOAddr,STRING _Name),NAME('Cla$BindV')

_UFOAddr - адрес UFO-переменной, полученный из RTL::Mem2UfoAddr()
_Name - строковое имя новой переменной
Обращаю внимание, что _Name имеет тип ОБЫЧНОЙ STRING, а не CSTRING!  И, кстати, CLIP() делать не обязательно - эта функция сама обрежет конечные пробелы.

И, опять-же, как и с памятью, в конце программы не надо забыть освободить память, занятую новым именем:

RTL::UnBind(STRING _Name),NAME('Cla$UnbindV')

_Name - строковое имя освобождаемой переменной

======================================================================
Вот, пожалуй, и все!
Маленький примерчик. Так сказать - для усвоения темы :)  Сразу предупреждаю - пример простейший и скелетный. Поэтому нет никаких проверок типа дублирования имен и пр.

Предположим, есть очередь, в которой содержаться имена новых переменных, которые необходимо создать для дальнейшего использования:

MAP
  MODULE('Clarion RTL')
    RTL::NewMem(UNSIGNED _Size),ULONG,NAME('Cla$NewMemZ')
    RTL::NewStr(UNSIGNED _Size),ULONG,NAME('Cla$NewMemB')
    RTL::FreeMem(ULONG _Addr),NAME('_free')
    RTL::Mem2UfoAddr(ULONG _VarAddr,BYTE _VarType,ULONG _DecFloat=0, |
    UNSIGNED _VarSize,BYTE=0),ULONG,RAW,NAME('Cla$Mem2Ufo')
    RTL::FreeUfo(ULONG _UFOAddr),RAW,NAME('Cla$FreeUfo')
    RTL::Bind(ULONG _UFOAddr,STRING _Name),NAME('Cla$BindV')
    RTL::UnBind(STRING _Name),NAME('Cla$UnbindV')
    RTL::GetBindVar(STRING _cVarName),*?,RAW,NAME('Cla$EvaluateVariable')
  END
END

Var1  ANY
sVar1 STRING(40)
Var2  ANY
sVar2 STRING(40)

VarNamesQue QUEUE,PRE(VAR)
Name     STRING(40) ! Имя переменной
Type     LONG ! Тип
Size     LONG ! Размер
DecFloat BYTE ! Для DECIMAL/PDECIMAL
Addr     LONG ! Здесь будет адрес блока памяти
UFOAddr  LONG ! Здесь будет адрес UFO-оболочки для переменной
           END
!
! Последние два поля при создании очереди инициализируются нулями.
!

CODE
...
Loop Var# = 1 to Records(VarNameQue)
  Get(VarNameQue,Var#)
  if ~VAR:Name OR ~VAR:Type OR ~VAR:Size Then Cycle.
  if VAR:Type = TYPE:STRING
    VAR:Addr = RTL::NewStr(VAR:Size)
  else
    VAR:Addr = RTL::NewMem(VAR:Size)
  .
  if ~VAR:Addr then Cycle. ! Память не выделена
  VAR:UFOAddr = RTL::Mem2UfoAddr(VAR:Addr,VAR:Type,VAR:DecFloat,VAR:Size)
  if ~VAR:UFOAddr ! UFO-оболочка не создана
    RTL::FreeMem(VAR:Addr)
    Cycle
  .
  RTL::Bind(VAR:UFOAddr,VAR:Name)
  Put(VarNameQue)   ! Обновить запись
.

Get(VarNameQue,1); sVar1 = VAR:Name
Get(VarNameQue,2); sVar2 = VAR:Name
Message(Evaluate(Clip(sVar1) &'+'& Clip(sVar2))) ! Var1 + Var2

! или

Get(VarNameQue,1); Var1 &= RTL::GetBindVar(Clip(VAR:Name)&'<0>')
Get(VarNameQue,2); Var2 &= RTL::GetBindVar(Clip(VAR:Name)&'<0>')
! ВНИМАНИЕ!!! Если какая-либо переменная не найдена и ANY &= Null,
! без проверки на Message() получим GPF.
if ~(Var1 &= Null) AND ~(Var2 &= Null)
  Message(Var1 + Var2) ! Var1 + Var2
.

! В конце надо освобождать за собой занятую память:

  Loop Var# = 1 to Records(VarNameQue)
    Get(VarNameQue,Var#)
    if ~VAR:Addr then Cycle.
    RTL::FreeMem(VAR:Addr); Clear(VAR:Addr)
    if ~VAR:UFOAddr then Cycle.
    RTL::FreeUfo(VAR:UFOAddr); Clear(VAR:UFOAddr)
    RTL::UnBind(Clip(VAR:Name))
  .

Олег А. Руденко. Oleg_Rudenko@chat.ru, Oleg_Rudenko@mail.ru 

Как установить свои шрифты из программы

Вопрос:
Задача такая -  При запуске проверить наличие шрифта в винде и если нет такового установить.

Ответ:
Анализировать ничего не надо, а просто грузить:

  AddFontResource

и в конце программы выгружать

  RemoveFontResource

данные шрифты будут видны ТОЛЬКО в этой программе

Andrew Myalin, andrew@arsis.ru

Ответ 2:
Точно.  А ещё опыт подсказывает, что это следует сделать для всех шрифтов текущего каталога, тогда проблема решается ещё проще - просто подложить шрифты в каталог программы и забыть...

The AddFontResource function adds the font resource from the specified file to the system font table. The font can subsequently be used for text output by any Win32-based application. (Из MSDN)

Вот фрагменты из реальной программы

MODULE('Windows.DLL')
  AddFontResource(*CSTRING),SIGNED,PASCAL,RAW,NAME('AddFontResourceA')
  RemoveFontResource(*CSTRING),BOOL,PASCAL,RAW,NAME('RemoveFontResourceA')
End

LoadFonts  Procedure
ttfQ Queue(ff_:Queue),Pre(TtfQ)
End
Loc:FontName CString(16)

CODE
  Free(TTfQ)
  Directory(TtfQ,'*.ttf',0)
  Loop ttfQ#=1 To Records(TTFQ)
    Get(TtfQ,TTfQ#)
    Loc:FontName=Clip(TTfQ:Name)
    If AddFontResource(Loc:FontName).
 End
 Free(TtfQ)

Загружаются все шрифты из текущего каталога. Аналогично (заменив AddFontResource на RemoveFontResource) - деинсталлируются. Но, насколько я понял, Remove... можно и не делать, тогда шрифт останется доступным до перезагрузки.

C уважением,  Юрий Философов, yufil@tacis-dipol.ru 




 


Hosted by uCoz