Страница 2 из 3

Добавлено: Сб дек 06, 2008 20:42:22
PB_EXPERT
я так понял опять какойто библиотеки
Если появляется такое сообщение, то это значит что одна или несколько библиотек не подходят для данной версии компилятора.
Это значит что все нужные библиотеки установлены, но некоторые не расчитаны на текущую версию компилятора.
Если бы была обнаружена неизвестная функция, то было бы сообщение is not a function, array, macro or linked list.
Правда такое-же сообщение выводится если не обнаружена вызываемая процедура, массив, макрос или динамический список.

Определить какая библиотека выдаёт такую ошибку можно методом исключения - просто вызываем по отдельности функции из библиотек.

Вот несколько простых примеров.
Запустите их и напишите при компиляции какого кода было сообщение
The following PureLibrary is missing: LibraryExtension


Droopy

Код: Выделить всё

Debug GetSystemDirectory() ; Узнаём путь к системной папке
XP_Menu_Lib

Код: Выделить всё

Procedure GlavWindowCallback(WindowID, Message, wParam, lParam)
 XP_Menu_CB(WindowID, Message, wParam, lParam)
ProcedureReturn #PB_ProcessPureBasicEvents 
EndProcedure

OpenWindow(0, 0, 0,200, 100, "", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)

 If CreateMenu(0, WindowID(0))
   MenuTitle("Файл")
   MenuItem(4,"Новый")
   MenuItem(1,"Открыть")
   MenuItem(2,"Сохранить")
 EndIf
 SetWindowCallback(@GlavWindowCallback() ,0)
 XP_MenuRegister(MenuID(0), #XP_RegMenu, #XP_RegGeneralMenu,WindowID(0)) ; Регистрация главного меню


Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
IO_DLL_WRAPPER (код измеряет текущую температуру процессора)

Код: Выделить всё

#ADR_REG = $295 
#DATA_REG = $296 
  
Procedure Termo() 
 IO_PortOut(#ADR_REG, $2B) 
 x=IO_PortIn(#DATA_REG) 
 SetGadgetItemText(0,0,StrU(x, #Byte)+" °C",1) 
 IO_PortOut(#ADR_REG, $29) 
 x=IO_PortIn(#DATA_REG) 
 SetGadgetItemText(0,1,StrU(x, #Byte)+" °C",1) 
EndProcedure 
  
  
  
 OpenWindow(0,0,0,300,74,"Измерялка температур",#PB_Window_MinimizeGadget|#PB_Window_Invisible|#PB_Window_ScreenCentered) 
  CreateGadgetList(WindowID(0)) 
  
   ListIconGadget(0,2,2,296,70,"Имя",120,#PB_ListIcon_GridLines) : SetGadgetFont(0,LoadFont(0,"MS Sans Serif",12) ) 
   AddGadgetColumn(0, 1, "Температура", 140) 
    
   AddGadgetItem(0, 0, "Процессор") 
   AddGadgetItem(0, 1, "Aux") 
   Termo()
  HideWindow(0,0) 
  
  SetTimer_(WindowID(0),1,1000, @Termo() ) 
  
  Repeat 
   Event=WaitWindowEvent() 
    
  Until Event=#PB_Event_CloseWindow
LibEditorPlus

Код: Выделить всё

OpenWindow(0, 0, 0,200, 100, "", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
CreateGadgetList(WindowID(0))
  EditorGadget(1,10,10,180,80)
    Editor_Select(1,0,1,-1,-1)
 
Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow

Добавлено: Вс дек 07, 2008 08:24:20
alexval2006
получил собщение
The following PureLibrary is missing: LibraryExtension
при проверке библеотеки IO_DLL_WRAPPER
там две папки в архиве с библиотекой содержимое паки пурик басик я скопировал через тотал куда положено но там помимо паки пурикбасик есть еще папка TS_Sources я ее просто скопировал в папку с установленым пуриком может я неправильно ее устанавливаю ?

Добавлено: Вс дек 07, 2008 12:48:11
PB_EXPERT
при проверке библеотеки IO_DLL_WRAPPER
А эта библиотека была скачана по той ссылке что я дал несколькими постами выше или отсюда http://www.purearea.net/pb/download/use ... RAPPER.ZIP? Так вот, эта библиотека предназначена для версий 3.хх компилятора, а нам нужна для версий 4.хх.

В архиве библиотека работающая в PB4.00, PB4.10, PB4.20 и PB4.30.
Ещё одно прниемущество этой версии библиотеки в том, что сам драйвер - файл io.dll внедрён в библиотеку и нет необходимости его размещать в папке с программой или системной папке.
папка TS_Sources
В этой папке находится исходник библиотеки и копировать эту папку не обязактльно.

Добавлено: Вс дек 07, 2008 14:53:12
alexval2006
Скачал установил получил такое сообщении при проверке кода градусника
The following PureLibrary is missing: PBOSL_LOADDLLMEMORY

Добавлено: Вс дек 07, 2008 15:38:24
PB_EXPERT
Это значит что не обнаружена библиотека PBOSL.
Дело в том, что библиотеки взаимосвязанны и повтороно функции не копируются. Это позволяет предельно уменьшмть размер исполняемого файла за счёт исключения дублежа кода, но требует наличия всех используемых биюлиотек.

Бмблиотеку PBOSL можно скачать здесь http://www.pbosl.purearea.net/pbosl_win.zip
Она предназначена для PB4.00, PB4.10, PB4.20 и PB4.30.
Если я не ощибаюсь, то больше никакие библиотеки не понадобятся. :)

Добавлено: Вс дек 07, 2008 16:54:43
alexval2006
ура заработало только прога гардусника показует 255 градусов это нормально или глюк?

Добавлено: Вс дек 07, 2008 18:26:51
PB_EXPERT
только прога гардусника показует 255 градусов это нормально или глюк
Это ещё от материнской платы и процессора зависит.
На сколько мне известно этот трюк не прокатывает с процессором фирмы ADM, а на INTELловских процессорах обычно работает, если материнка позволает.

Добавлено: Вс дек 07, 2008 19:15:42
alexval2006
у меня AMD Atlon 64 3000+ 1,81Ггц
я хочу с помощь пурика натакать софтину для упрвления световым табло на 380 ламп у меня софтина есть для этога но она на Q басике а он устарел и по возможностям и по внешнему виду выходящих от туда приложений поэтому я решил воспользоватся пуриком понравился вид выходящих в итоге програм управление будет тоже через ЛПТ порт такшто эта програма управления детской машинкой неплохой пример для меня благодарствую буду изучать кстати хотел добавить в програму свою будущую элемент светодиод LEDgadget но там чото касяк какой то нехочет может это из-за версии компилятора потомушто на той странички они почти все рашитаны на 4 версию и более раннии версии
прилагаю файл со с ветодиодной индикациеей пути я исправил обращение к файлам картинок светодиодов потом копилятор серавно ругается на строку дальше по тексту
DataSection
ledred:IncludeBinary "Иконки_2\ledred.ico"
ledredoff:IncludeBinary "Иконки_2\leddarkred.ico"
ledgreen:IncludeBinary "Иконки_2\ledgreen.ico"
ledgreenoff:IncludeBinary "Иконки_2\ledgreenoff.ico"
ledyellow:IncludeBinary "Иконки_2\ledyellow.ico"
ledyellowoff:IncludeBinary "Иконки_2\ledyellowoff.ico"
ledblue:IncludeBinary "Иконки_2\ledblue.ico"
ledblueoff:IncludeBinary "Иконки_2\ledblueoff.ico"
EndDataSection

ProcedureDLL initLED()
Structure gauge
imagegad.l
imageid.l
width.l
height.l
imagehwnd.l
precision.l
ticks.l
textgad.l
texthwnd.l
State.l
numstates.l
EndStructure
Dim ledpics.l(10)
NewList led.gauge()
ledpics(0)=CatchImage(#PB_Any,?ledred)
ledpics(1)=CatchImage(#PB_Any,?ledgreen)
ledpics(2)=CatchImage(#PB_Any,?ledyellow)
;ledpics(3)=CatchImage(#PB_Any,?ledgray)
ledpics(4)=CatchImage(#PB_Any,?ledredoff)
ledpics(5)=CatchImage(#PB_Any,?ledgreenoff)
ledpics(6)=CatchImage(#PB_Any,?ledyellowoff)
ledpics(7)=CatchImage(#PB_Any,?ledblue)
ledpics(8)=CatchImage(#PB_Any,?ledblueoff)
EndProcedure
ругается на эту строку ProcedureDLL initLED()

Добавлено: Вс дек 07, 2008 20:35:14
PB_EXPERT
добавить в програму свою будущую элемент светодиод LEDgadget но там чото касяк какой то нехочет может это из-за версии компилятора потомушто на той странички они почти все рашитаны на 4 версию и более раннии версии
Как раз в том, что расчитано на более раную версию и проблема.
Но поскольку там есть исходник библиотеки, то проблема решаемая.
Немного изменил исходник. :)
Теперь компилируется в PB4.хх
Но как я понимаю его нужно ещё немного модифицировать, поскольку сейчас можно изменять цвета только кликом мышки, а нам нужно с помощью программы.
Библиотеку функций из этого исходника пока не удалось создать.
Вылетает ошибка при доступе к памяти если запускать пример с библиотекой, но если просто подключать исходник как всполагательный файл, то всё работает.

ругается на эту строку ProcedureDLL initLED()
Как я понимаю файлы Ledgadget и ledres.res являющиеся библиотекой функций были скопированы в соответствующие папки пурика?
Если да, то скорее всего было сообщение что функция с таким именем уже существует.

Добавлено: Вс дек 07, 2008 22:07:49
alexval2006
скачал архив файл Ledgadget забросил в паку UserLibraries открыл файл ledgadget.pb запустил компилятор поучил такой ответ строка 7
Invalid name: same as an external command.
фрагмент кода эта сторка самая верхняя
ProcedureDLL initLED()
Structure gauge
imagegad.l
imageid.l
width.l
height.l
imagehwnd.l
precision.l
ticks.l
textgad.l
texthwnd.l
State.l
numstates.l
EndStructure

Добавлено: Вс дек 07, 2008 23:00:52
PB_EXPERT
Я вот что подумал.
Зачем нам в этом случае вообще нужна библиотека функций.
Ведь рисунок светодиода можно отобразить с помощью ImageGadget.
Изменять рисунок можно с помощью функции SetGadgetState.

Вот пример

Код: Выделить всё

; Загружаем рисунки из памяти
CatchImage(1,?ledred)
CatchImage(2,?ledgreen)
CatchImage(3,?ledyellow)
CatchImage(4,?ledredoff)
CatchImage(5,?ledgreenoff)
CatchImage(6,?ledyellowoff)
CatchImage(7,?ledblue)
CatchImage(8,?ledblueoff)

; Открываем окно
OpenWindow(0, 0, 0,200, 100, "", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered) 
CreateGadgetList(WindowID(0))
ImageGadget(0,10,15,30,30,ImageID(1)) ; Отображаем рисунок в окне
ButtonGadget(1,80,10,100,24,"Сменить цвет") ; Кнопка

Count=2 ; Счётчик текущего рисунка
Repeat 
 Event=WaitWindowEvent() ; Идентификатор текущего события
 Gadget=EventGadget()    ; Идентификатор гаджета, в котором произошло событие
  
  If Event=#PB_Event_Gadget And Gadget=1 ; Был щелчок по экранной кнопке
   SetGadgetState(0,ImageID(Count)) ; Отображаем новый рисунок
   Count=Count+1 ; Увеличиваем значение переменной-счётчика
     If Count>8 ; Если значение вышло за допустимые пределы
      Count=1   ; то записываем 1
     EndIf
  EndIf
  
Until Event=#PB_Event_CloseWindow ; Собфтие закрытия окна
End ; Завершаем работу программы


; Информационная секция. При компиляции файлы будут помещены в EXE и для дальнейшей
; работы программы внешние файлы уже не нужны, ведь их копии находятся в EXEшнике.

DataSection 
ledred:IncludeBinary "Иконки\ledred.ico"
ledredoff:IncludeBinary "Иконки\leddarkred.ico"
ledgreen:IncludeBinary "Иконки\ledgreen.ico"
ledgreenoff:IncludeBinary "Иконки\ledgreenoff.ico"
ledyellow:IncludeBinary "Иконки\ledyellow.ico"
ledyellowoff:IncludeBinary "Иконки\ledyellowoff.ico"
ledblue:IncludeBinary "Иконки\ledblue.ico"
ledblueoff:IncludeBinary "Иконки\ledblueoff.ico"
EndDataSection
скачал архив файл Ledgadget забросил в паку UserLibraries открыл файл ledgadget.pb запустил компилятор поучил такой ответ строка 7
Не нужно ничего копировать в папки пурика.
Это сообщение означает что такая функций существует в библиотеке и дублируется в коде.

Добавлено: Ср дек 10, 2008 16:40:20
alexval2006
есть вопрос Назначение библиотек Droopys и pbosl_win
и еще вопросик где находится ссылка на значок програмы в вашем случае ресунок машинки просьба показать этот фрагмент кода

Добавлено: Ср дек 10, 2008 18:41:49
PB_EXPERT
В этих библиотеках есть примерно по 300 дополнительных функций разного назначения, т. е. устанавливаешь библиотеку и становятся доступными дополнительные функции.
Использование дополнительных функций не только сокращает время разработки программы, но и требует минимум знаний, ведь не нужно думать как сделать то или иное, просто вызываем функцию и всё.

Скажем, нам нужно узнать текущую загрузку процессора, но мы не знаем как получать эту информацию.
Не проблема. :)
В библиотеке pbosl есть функция CpuUsage(), которая получает такую информацию.

Код: Выделить всё

; ВНИМАНИЕ этот код работает только в среде PureBasic, если создать EXEшник, то работать не будет
; связанно это с тем, что для вывода инфы использован оператор Debug
Repeat ; Начало цикла Repeat - Until
 Debug CpuUsage()
 Delay(1000)
Until GetAsyncKeyState_(#VK_ESCAPE) ; Завершаем работу проги если нажата кнопка Esc на клаве


Описание функций можно найти в справке, прилагаемой к библиотеке.
Вызвать справку можно в меню Помощь --> Внешняя справка в открывшемся меню будет список справок для установленых дополнительных библиотек с функциями.
Эти справки наподятся в папке C:\Program Files\PureBasic\Help

Можно вызывать стравку и по другому.
Просто ставим текстовый курсор на функцию, и нажимаем на F1 на клаве.
Справка будет открыта на странице описания интерисующей функции.
Это справедливо как для встроеных функций, так и для функций дополнительных библиотек.

Добавлено: Ср дек 10, 2008 18:43:45
alexval2006
еще вопросик где находится ссылка на значок програмы в вашем случае ресунок машинки просьба показать этот фрагмент кода ?

Добавлено: Ср дек 10, 2008 19:25:53
PB_EXPERT
где находится ссылка на значок програмы.
Это задаётся в опциях проекта, данные которых хранятся в конце исходника и чтобы их увидеть нужно открыть исходник в "Блокноте" и прокрутить до конца текст.

Для добавления значка нужно открыть окно "Устаноки компилятора" и в вести путь в поле "использовать иконку".
Вызывается окно с помощью меню Компилятор --> Настройки компилятора

Изображение

Добавлено: Ср дек 10, 2008 22:56:26
alexval2006
со значком програмы разобрался спасибо вот возник еще вопрос можно пример кода где происходит запись логической "1" в LPT порт и пример чтения логического уровня с порта заранее благодарен.
Хочу научить прогу общятся с микросхемой КР580ВВ55А адаптером паралельного Ввода вывода она имеет 24логических выхода.

Добавлено: Ср дек 10, 2008 23:53:07
yeskela
alexval2006 писал(а):со значком програмы разобрался спасибо вот возник еще вопрос можно пример кода где происходит запись логической "1" в LPT порт и пример чтения логического уровня с порта заранее благодарен.
Хочу научить прогу общятся с микросхемой КР580ВВ55А адаптером паралельного Ввода вывода она имеет 24логических выхода.
Могу подсказать как это сделать на Delphi, Работать будет под любыми виндами.

На всякий случай напишу, малоли кто не знает...
LPT состоит из 3-х регистров:
DATA (Двунаправленный)
Status (Только чтение)
Control (Двунаправленный)

Обращение к Data через базовый адрес порта (например h378 для LPT1)
Обращение к Status - базовый адрес +1
Обращение к Control - базовый адрес +2

Data - это пины 9,8,7,6,5,4,3,2 (т.е. если в этот регистр записать b1000010 то на 9 и 3 пине будет лог.1)

Status - пины 15,13,12,10,11 (т.е. если из этого регистра считать значение b00001ххх значит все эти 5 пинов замкнуты на землю. Значение бита отвечающего за 11 пин инвертировано. значение последних 3-х битов ни за что не отвечают, и всегда то-ли 0 то-ли 1, не помню...)

Control - пины 17, 16, 14, 1 (т.е. что-бы выставить на этих пинах "1" надо записать в регистр Control b000z0100. Значение в байте z управляет регистром Data на чтение и запись. z=1-чтение, z=0-запись. Старшие три бита ни на что не влияют)

Внимание! На пинах 1, 11, 14 и 17 сигналы инвертированы!
Пины 18..25 - это земля.
В некоторых очень древних портах Control и Data однонаправленные, но врят-ли такие порты еще где-то сохранились...

Добавлено: Чт дек 11, 2008 10:58:37
PB_EXPERT
Немного инфы о работе с LPT портом есть в архиве.
Правда, там примеры для VB5 и работа с драйвером inpout32.dll, но это не столь важно, главное есть описание самого порта. :)

Для работы с LPT портом в среде PureBasic я рекомендую использовать библиотеку IO_DLL_WRAPPER.
Ссылку давал выше в этой теме.

Прежде всего нужно инициализировать драйвер где-то в начале программы с помощью функции IO_IsDriverInstalled(), результат работы которой должен быть не равным нулю. Если ноль, тогда возникли проблемы при активации драйвера.

После этого уже можно работать с самим портом, читать и писать данные.
Читается один файт с помощью функции IO_PortIn(wPort) где wPort - адрес порта.
Результат работы функции - прочитаная информация из порта.

Записываются данные с помощью функции IO_PortOut(wPort, bData) где wPort - адрес порта; bData - записываемый байт данных.


Если нужно, то можно работать и побитно.
Чтобы обнулить бит, нужно использовать функцию IO_ClrPortBit(wPort, bBit) где wPort - адрес порта; bBit - номер бита (0...7), который нужно обнулить.

Чтобы установить бит в лог. 1, нужно использовать функцию IO_SetPortBit(wPort, bBit) где wPort - адрес порта; bBit - номер бита (0...7), который нужно установить в лог. 1.

Чтобы инвертировать бит нужно использовать функцию IO_NotPortBit(wPort, bBit) где wPort - адрес порта; bBit - номер бита (0...7), который нужно инвертировать.

Чтобы прочитать бит нужно использовать функцию IO_GetPortBit(wPort, bBit) где wPort - адрес порта; bBit - номер бита (0...7), который нужно прочитать. В качестве результата, функция передаст состояние бита (0 или 1).


В библиотеке есть ещё функции для чтения (IO_PortWordIn) и записи (IO_PortWordOut) в порт двух байтных чисел, и функции для чтения (IO_PortDWordIn) и записи (IO_PortDWordOut) в порт четырёх байтных чисел, а так же смещения данных влево (IO_LeftPortShift) и вправо (IO_RightPortShift), но вряд ли это понадобится при работе с LPT портом, это для каких-то других портов наверное нужно.


Вот пример записи и чтения данных из информационного регистра LPT порта с использованием функций IO_PortIn и IO_PortOut

Код: Выделить всё

;******************************************************
;* Пример работы с библиотекой функций IO_DLL_WRAPPER *
;******************************************************

 If IO_IsDriverInstalled()=0 ; Активируем драйвер
  MessageRequester("Ошибка", "Не удалось активировать "+Chr(10)+"драйвер LPT порта", #MB_OK|#MB_ICONERROR)
  End ; Завершаем работу программы
 EndIf
 
; Открываем окно
 If OpenWindow(1,200,200,380,150,"Работа LPT используя IO_DLL_WRAPPER", #PB_Window_MinimizeGadget)
  If CreateGadgetList(WindowID(1)) ; Создаём новый список гаджетов (кнопок, выпадающих списков и т. д.)
  
  TextGadget(1,10,24,58,16,"LPT порт") ; Надпись
  ComboBoxGadget(2,70,20,80,100) ; Выпадающий список
     AddGadgetItem(2,-1,"LPT1")  ; Заполнение списка
     AddGadgetItem(2,-1,"LPT2")
     SetGadgetState(2,0) : AddressLPT=$378 ; Активируем нулевой пункт списка
   
  TextGadget(3,10,80,130,16,"Запись данных в порт")
  StringGadget(4,140,74,30,20,"",#PB_String_Numeric) ; Поле для ввода данных
     SendMessage_(GadgetID(4), #EM_SETLIMITTEXT, 3, 0) ; С помощью API функции ограничиваем число символов с поле
  ButtonGadget(5,180,74,80,20,"Записать") ; Кнопка
  
  
  TextGadget(6,10,120,138,16,"Чтение данных из порта")
  StringGadget(7,140,114,30,20,"",#PB_String_ReadOnly) : SetGadgetColor(7,#PB_Gadget_BackColor,RGB(238, 238, 238))
  ButtonGadget(8,180,114,80,20,"Читать")
  
  
   Repeat ;- Начало бесконечного (завершится только при закрытии программы) цикла Repeat - Until
    Event=WaitWindowEvent() ; Идентификатор события в программе
    Gadget=EventGadget()    ; Идентификатор гаджета, в котором произошло событие
    Type=EventType()        ; Идентификатор типа события
    
    
    If Event=#PB_Event_Gadget ; Произошло событие в гаджете (скорее всего клик мышкой по нему)
        Select Gadget
          Case 2 ; Событие в выпадающем списке
              If Type=1 ; Список закрылся с выбором пункта
               Select GetGadgetState(2) ; Узнаём какой пункт был выбран
                 Case 0
                   AddressLPT=$378
                 Case 1
                   AddressLPT=$278
               EndSelect
              EndIf
            
          Case 5 ; Событие в кнопке "Записать"
            DataOut=Val(GetGadgetText(4)) ; Читаем текст из поля и преобразовываем его в число
             If DataOut>255 ; Если число больше 255
              DataOut=255   ; делаем его равным 255
             EndIf
             IO_PortOut(AddressLPT, DataOut) ; Отправляем число в порт
             
          Case 8 ; Событие в кнопке "Читать"
            DataIn.c=IO_PortIn(AddressLPT) ; Читаем данные из порта и помещаем в переменную типа Character (хранит один байт - целое число в пределах 0...255)
            SetGadgetText(7,Str(DataIn))    ; Отображаем в окне, предватительно число преобразовав в строку
            
        EndSelect
    EndIf
    
   Until Event=#PB_Event_CloseWindow ; Прерываем основной цикл Repeat - Until если нужно закрыть окно
  EndIf
 EndIf
End ; Завершаем работу программы

Добавлено: Чт дек 11, 2008 23:38:25
Frredo
Всем доброй ночи! Обращаюсь к вам за помощью как к знающим людям. У меня идентичная проблема что и у автора, но мне нужно написать такую же программу только на С. Сам я этот язык чуть чуть знаю, но как написать такую программу даже не представляю. Вот и обращаюсь к вам за помощью. Может хоть в общих чертах расскажете как да что. Пульт подключается по LPT порту. Схема интерфейса прилеплена. Заранее спасибо.

Добавлено: Пт дек 12, 2008 09:16:23
yeskela
Frredo писал(а):Всем доброй ночи! Обращаюсь к вам за помощью как к знающим людям. У меня идентичная проблема что и у автора, но мне нужно написать такую же программу только на С. Сам я этот язык чуть чуть знаю, но как написать такую программу даже не представляю. Вот и обращаюсь к вам за помощью. Может хоть в общих чертах расскажете как да что. Пульт подключается по LPT порту. Схема интерфейса прилеплена. Заранее спасибо.
Распиновку LPT и в какие регистры за что отвечают я писал чуть выше. Что касается программной часть - то самый простой способ - это использовать существующую DLL для работы с портом (библиотека в приложении)
как экспортировать функции из dll на С я не знаю, нодумаю в нете по этому полно инфы.
На Delphi это делается так:
function Inp32(PortAdr: word): byte; stdcall; external 'LPT.dll'; - Запись
function Out32(PortAdr: word; Data: byte): byte; stdcall; external 'LPT.dll'; - чтение

Где PortAdr - это базовый адрес порта (h378-LPT1, h278-LPT2, h3BC-LPT3) т.е для LPT1 PortAdr - может быть равен h378, h378+1 и h378+2 (почему - см. выше.)