Несколько мелочей на всякий случай

В этой статье хочется показать кое-какие полезности, которые могут пригодиться для программировании.

 

Способы вывода русских символов в консоль и графическое окно.

Один из способов я упоминал в статье файлы, это сохранение исходника в файле с форматом Unicode. Я покажу другие.
Прежде всего есть превосходная библиотека ALBOM_FONT с открытым исходным кодом на FreeBasic. Используя ее, достаточно после команды Screen или ScreenRes вставить макрос: #Include Once "albom_font.bi" и операторы Print и Input начнут признавать русские символы в графическом окне. Скачать можно в соответствующей колонке сайта.
Следующие два способа используют преобразование с помощью функций API.

1) Используя функцию MultiByteToWideChar

#INCLUDE "windows.bi"
Function PrintRus(Byval text As String) As Wstring Ptr 
  Var blen = (Len(text)*2)+2
  Dim As Wstring Ptr wbuf
  wbuf  = Allocate( blen )
  MultiByteToWideChar(CP_ACP, 0,text , -1, wbuf, blen)
  Print *wbuf
  Deallocate(wbuf)
End Function

PrintRus ("Выводим русские символы в консоль")
Sleep


Ничего страшного в примере нет. В функции выделяется буфер в формате юникодовой строки, куда и заносится преобразованное значение функцией  MultiByteToWideChar. Есть и обратная операция с помощью WideCharToMultiByte.

2) Используя функцию CharToOem

#INCLUDE "windows.bi"
Dim As String st="Выводим русские символы в консоль"
CharToOem(st,st)
Print st: Sleep


Эта функция хороша тем, что может преобразовывать прямо в исходный буфер как в примере выше. Если же надо преобразовывать символы в другой буфер, то его надо выделять вручную (например с помощью Allocate). Или если заранее известно кол-во символов в строке, то можно установить фиксированный буфер строки (dim as string*256 dest) Есть и обратная операция преобразования с помощью функции OemToChar.

 

Макрос IIF

Данный макрос это расширение стандартных условных операторов. Позаимствован из языка Си. Его синтаксис:

result = IIf ( condition, if_true, if_false )

  • Result - результат работы макроса
  • condition - сравниваемая инструкция или задаваемое условие
  • if_true - result будет равен этому параметру , если condition истинно
  • if_false - result будет равен этому параметру , если condition ложно

Пример:

? IIF(3>5,3,5)
Sleep


В данном примере в первом параметре идет сравнение двух чисел . Поскольку результат 3>5 является ложным, то макрос вернул третий параметр.

 

Открытие дополнительного окна консоли

Иногда при выводе графики может понадобится выводить текстовую информацию в другое окно. Это может быть какая-нибудь отладочная информация. Для этого можно воспользоваться функцией Open Cons.

Синтаксис:

Open Cons For output As #1

Open Cons For input As #1

Ничего особенного, как при открытии обычных файлов для записи или чтения.

Пример:

Dim a As String
Screen 1
Draw "BM160,100"
Dim As String drawbox = "U80R50D80L50"
Draw "X" & Varptr(drawbox)
Open Cons For Output As #1
Print #1,"Please write something and press ENTER"
Line Input #1,a
Print #1, "You wrote : ";a
Close
Sleep


Как видите, здесь уже при использовании оператора Print или Input надо указывать идентификатор консоли.

 

Пенсионер GOSUB может еще поработать

На оф. сайте FreeBasic один из участников показал три примера использования отправленного в отставку оператора GOSUB. Каждая из этих симуляцией для своей версии установки компилятора. Все три компилируем как обычно fbc -s console

1 симуляция для версии совместимой с QB:

#Lang "qb"
Dim C As Integer
C = 5
For I As Integer = 0 To 5
  Gosub CounterDown
Next I
Sleep
End
CounterDown:
  Print C
  Sleep 1
  C -= 1
Return


2 симуляция для версии совместимой с FbLite:

#Lang "fblite"
Option Gosub
Dim C As Integer = 5
For I As Integer = 0 To 5
   Gosub CounterDown
Next I
Sleep
End
CounterDown:
   Print C
   Sleep 1000
   C -= 1
Return


3 симуляция для текущей версии FreeBasic , но тут следует оговориться. Напрямую использовать команды Gosub и Return нельзя. Можно конечно жахнуть оба макроса Gosub и Return , и описать их заново, но тогда останемся без функций и процедур или придется и под них макросы писать :) Проще дать другое имя, как в примере ниже:

#DEFINE _GoSub Asm Call
#DEFINE _Label Asm
#DEFINE _Return Asm Ret
Dim C As Integer = 5
For I As Integer = 0 To 5
   _GoSub CounterDown
Next I
Sleep
End
_Label CounterDown:
   Print C
   Sleep 1000
   C -= 1
_Return

 

Печать

По своей сути в Freebasic печать сделана очень неважно, можно сказать почти никак. Именно поэтому, хоть у меня и нет принтера(точнее сломан) , я в своей библиотеке window9 реализовал самое необходимое для печати. Что касается средств FreeBasic:

Это все та же команда Open только с постфиксом Lpt .

Запускается принтер так:

Open Lpt( "LPT:" + printerName + ",EMU=TTY", For Output, As #1 )

Разбив первый параметр строки, получим:

  • "LPT:" - параметр для Windows и Linux ,  для DOS  "LPT1" 
  • printerName - имя принтера
  • ",EMU=TTY"  - специфично для Windows , будет использоваться GDI для преобразования текста в рисунок
  • Остальное должно быть понятно из главы файлы   

Печатается текст так же как и в файлы:

Print #1, "Hello, world!"

И освобождается дескриптор:

Close #1

Если не знаете имя принтера, не нужно пытаться подбирать его как пароль. Этим вы можете вызвать BSOD

Лучшим вариантом создать диалог для выбора принтера и выбрать в нем существующий. Пример ниже создал автор (v1ctor) FreeBasic:

#INCLUDE "windows.bi"
#INCLUDE "win/commdlg.bi"
Function selectPrinter( ) As String
    Dim As PrintDlg pd
    pd.lStructSize = Sizeof( PrintDlg )
    If PrintDlg(@pd) = FALSE Then
        Exit Function
    End If
    Dim As DEVNAMES Ptr dn = GlobalLock( pd.hDevNames )
    Function = *Cast( Zstring Ptr,_
    Cast( Byte Ptr, dn )+ dn->wDeviceOffset )
    GlobalUnlock( dn )
End Function
Dim As String printerName
printerName = selectPrinter( )
If( Len( printerName ) = 0 ) Then
    Print "No printer selected"
    End 1
End If
If( Open Lpt( "LPT:" + printerName + _
    ",EMU=TTY", For Output, As #1 ) <> 0 ) Then
    Print "Error: Open failed"
    End 1
End If
Print #1, "Hello, world!"
Close #1

 

Еще одна особенность Constructor и Destructor

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

Пример:

Sub BB Destructor
    Print "End"
    Sleep
End Sub
Print "1 string"
Print "2 string"
Print "3 string"
Sub AA Constructor
    Print "first string"
End Sub


Как видите конструктор стоит последним , но выполняется первым, а деструктор наоборот. И это еще не все. Если установить несколько конструкторов и деструкторов, то можно и между ними устанавливать приоритет. Для конструкторов меньший приоритет обеспечивает запуск самым первым. Для деструкторов меньший приоритет обеспечивает завершение самым последним. Приоритет должен быть в диапазоне от 101 и выше.

Пример:

Print "1 string"
Print "2 string"
Print "3 string"
Sub AA Constructor 102
    Print "Second srting"    
End Sub
Sub BB Constructor 101    
    Print "first string"
End Sub
Sleep


Пожалуй все для этой статьи. Всего доброго!

содержание | назад | вперед