Ассоциация ЭБНИТ    ИРБИС-корпорация    Вики-Ирбис    Online/CHM справка Ирбис   
Опыт и разработки пользователей ИРБИС :  ИРБИС Irbis
 
Пишем модуль для экспорта данных с сайта издательства "ЛАНЬ" как пример реализации плагина к ИРБИС64
Пользователь: S-presso (IP-адрес скрыт)
Дата: 12, December, 2012 21:36

Вероятно, кому-нибудь из вас, как и мне, хотелось бы расширить функциональность Ирбиса своими собственными программными дополнениями. Но что, если вы предпочитаете вести разработку на современных управляемых языках программирования, таких как C# ? Можно ли встраивать создаваемые на таких языках модули в Ирбис? Чтобы разобраться в этом вопросе, я и создал данную тему. Впрочем, те, кто планирует писать свои дополнения на Delphi, тоже могут найти здесь что-то полезное для себя. Для них такое задание: переписать описываемый модуль полностью на Delphiwinking smiley.

Прежде всего, dll, написанная на C#, в отличие от dll на Delphi и других языках с компиляцией в машинный код, представляет собой управляемую сборку. Это не набор функций (обычно называемых нативными), которые мы можем напрямую вызывать из Каталогизатора или других приложений, написанных на неуправляемых языках. В данном случае мы имеем отдельный класс с набором методов, являющихся управляемыми и, следовательно, недоступных непосредственно из машинного кода. Их выполнению должна предшествовать загрузка исполняемой среды CLR, в которой работают все управляемые приложения .NET. Обычно для этого нужные .NET сборки упаковывают в COM-компоненты. Это достаточно долгий путь, которому посвящены отдельные статьи. Нет ли способа проще? Оказывается, есть. Он состоит в том, чтобы напрямую экспортировать отдельные методы нашей сборки в виде неуправляемых. Существует широко распространённое мнение о том, что это невозможно. Однако оно не соответствует действительности. Давайте немного разберёмся.

Если речь идёт о встроенных средствах языков C# и VB.NET, то, действительно, они не позволяют нам помечать методы как неуправляемые. Однако такие средства есть в ассемблере IL, в код которого транслируются все программы на этих языках. Для этого существует специальный атрибут, который говорит нам о том, что методы следует экспортировать как неуправляемые (нативные). Раньше для этого нужно было откомпилировать модуль, дизассемблировать его в IL, добавить необходимые атрибуты и собрать снова. Естественно, это требовало определённых познаний языка IL (стекового ассемблера). К счастью, нашёлся добрый человек, который создал средства, позволяющие автоматизировать этот процесс. Их описанию посвящена статья [www.codeproject.com]. Теперь всё, что нам требуется, это подключить в Visual Studio к нашему проекту dll-плагина сборку ExportDllAttribute, после чего отдельные методы можно помечать специальным атрибутом.

В нашем демонстрационном проекте мы будем из функции, вызываемой Ирбисом (её имя, как и имя её библиотеки dll, указывается в конфигурационном файле), загружать окно с браузером, в котором мы можем осуществлять навигацию по страницам сайта издательства "ЛАНЬ" и копировать библиографические данные отдельных изданий, которые мы можем напрямую импортировать в Ирбис. Для этого наша функция на C# помечена специальным атрибутом и имеет следующий вид:

[ExportDllAttribute("LANExport", System.Runtime.InteropServices.CallingConvention.Cdecl)]
        public static int LANExport(IntPtr buf1, ref IntPtr buf2, int bufsize)
        {
            Form1 form = new Form1();
            
            byte[] textBytes = new byte[bufsize];
            Marshal.Copy(buf1, textBytes, 0, bufsize);
            byte[] textAnsiArray = Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding(1251), textBytes);
            form.record = new StringBuilder(Encoding.GetEncoding(1251).GetString(textAnsiArray));
            form.ShowDialog();

            if (form.readyToPass)
            {
                buf2 = Marshal.AllocHGlobal(bufsize);
                textBytes = Encoding.GetEncoding(1251).GetBytes(form.record.ToString());
                textBytes = Encoding.Convert(Encoding.GetEncoding(1251), Encoding.UTF8, textBytes);
                Marshal.Copy(textBytes, 0, buf2, textBytes.Length);
                return 1;
            }
            return 0;
        }

Как мы видим, функция ExportBO имеет два параметра типа IntPtr, представляющих собой исходную и конечную записи для Ирбиса, и один целочисленный параметр - размер записи. Вызывается оконная форма и ей передаётся управление. По выходу из окна, если параметр readyToPass имеет значение true, сохранённое значение записи преобразуется к типу IntPtr и кодировке UTF-8 и затем экспортируется путём указания 1 в качестве кода возврата в операторе return 1; В случае отсутствия изменений выход из функции осуществляется оператором return 0;

Чтобы проверить работу нашего приложения (как известно, dll-библиотека не может быть запущена напрямую), мы добавили к решению небольшой проект Call_LAN с кнопкой и текстовым окном. При запуске приложения мы создаём пробную запись для передачи функции. Нажатием кнопки мы вызываем функцию ExportBO, а возвращаемые ей данные копируются в текстовое окно.

Внешний вид оконного приложения, вызываемого функцией ExportBO(), следующий:


Отметим, что библиографическое описание можно скопировать не с любой страницы сайта, а лишь со страниц, содержащих информацию о каком-либо отдельном издании:



Однако пока скомпилированный нами модуль LAN_Export_NET.dll может вызываться только из управляемых приложений, подобных нашему проекту Call_LAN. Чтобы сделать его доступным для неуправляемого кода, недостаточно просто пометить метод, как мы сделали. Надо ещё обработать его специальной утилитой (которая выполняет за нас всю "грязную" работу по взаимодействию с кодом IL). Для этого требуется зайти в папку с её исполняемым файлом и передать ей в командной строке в качестве параметра полный путь к файлу LAN_Export_NET.dll. Например, если вы разархивируете все мои приложенные файлы в папку D:\Temp, найдите там папку D:\Temp\ExportDll\ExportDll\bin\Debug\ и вызовите из неё утилиту следующим образом:

ExportDll.exe D:\Temp\LAN_Export2IRBIS\bin\Debug\LAN_Export_NET.dll


Небольшой нюанс: чтобы утилита сработала, в конфигурационном файле ExportDll.exe.config должны быть правильным образом настроены пути к файлам ilasm.exe и ildasm.exe. Это зависит от установленной у вас версии .NET и Windows. Второй путь - это обычно C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\ildasm.exe или C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\ildasm.exe.

Теперь надо скопировать полученный файл LAN_Export_NET.dll в папку Ирбиса и указать его в качестве значения параметра UMDLLn конфигурационного файла irbisc.ini (где n - порядковый номер кнопки, на которую навешан наш плагин). Надо также прописать там UMFUNCTION0=LANExport, UMPFT0=LAN и кинуть файл LAN.pft во вложенную папку Datai\Deposit\ (подробнее см. документацию и [irbis.gpntb.ru]). После этого теоретически всё должно работать, и если бы мы изначально создавали нашу dll на Delphi, то проблем бы, наверное, не было. А теперь к плохим новостямsmiling smiley.

Мне удалось реализовать таким образом лишь передачу данных из Ирбиса на входе в функцию, когда она отображает текущую запись в своём текстовом поле. Передачи её обратно мне достичь таким путём, увы, не удалось. Видимо, существует какая-нибудь особенность при передаче параметров из управляемого метода, не учтённая создателями Ирбиса. Если вам известен простой способ решения этой проблемы, пожалуйста, сообщите мне об этом. Так или иначе, мы создадим пока ещё одну программную прослойку на Delphi, которая и будет вызывать нашу управляемую сборку LAN_Export_NET.dll. Причём, поскольку вся логика содержится в управляемом коде, знание Delphi тут практически не требуется. Этот проект должен будет создавать библиотеку LAN_Export.dll и состоять из двух модулей - LAN_Export.dpr и LAN_Export1.pas. Вот их текст:

{LAN_Export.dpr}
library LAN_Export;

uses
  SysUtils,
  Classes,
  LAN_Export1 in 'LAN_Export1.pas';

Exports LANExport1 name 'LANExport';

{$R *.res}

begin
end.

{LAN_Export1.pas}
unit LAN_Export1;

interface
uses
  SysUtils,
  StrUtils;

function LANExport1(buf1,buf2: Pchar; size: integer): integer; stdcall;

implementation

function LANExport(buf1: Pchar; var buf2: string; size: integer): integer; stdcall; external 'LAN_Export_NET.DLL' ;

function LANExport1(buf1, buf2: Pchar; size: integer): integer;
var
  res : integer;
  rec : string;
begin
  res := LANExport(buf1, rec, size);
  StrLCopy(buf2,Pchar(rec),size);
  LANExport1 := res;
end;

end.

Скомпилируем LAN_Export.dll и также скопируем её в рабочую папку Ирбиса. Вы уже догадались, что именно этот файл мы будем вызывать по нажатию пользовательской кнопки Каталогизатора. Поскольку в этом модуле тоже имеется функция LANExport, достаточно будет изменить значение параметра UMDLL.

По идее после этого всё должно заработать. На практике же наш модуль срабатывает только один раз из нескольких попыток запуска, а в остальное время Каталогизатор наглухо висит с отображением на белом фоне сообщения "Выполняется режим пользователя". Думаю, это программный глюк Ирбиса - ведь посредством внешнего тестового модуля наша функция срабатывает всегда.

В любом случае, даже если у вас не получилось проделать описанный мной трюк, вы всё равно научились кое-чему новому. Возможно, этот опыт пригодится при написании на .NET плагинов для других (неуправляемых) приложений. Пока "приручить Ирбис" на 100% для работы с .NET-сборками мне не удалось. Но мне кажется, у данного направления есть перспектива. Например, насколько мне известно, программный интерфейс для ручки-сканера C-Pen существует только под .NET. И если мы хотим автоматизировать процесс каталогизации с помощью C-Pen (речь идёт именно об интеллектуальной автоматизации, а не о простом переносе отсканированных строк текста в Ирбис!), то приведённое решение, позволяющее воспользоваться интегрированным модулем лишь один раз за весь сеанс работы с Каталогизатором, думаю, пользователей не устроит. Мне кое-как удалось встроить таким образом модуль распознавания библиографического описания, предварительно убрав из него все сборки, подключающие OCR и spell-check, оставив только голое текстовое поле. Но и в таком виде он сработал всего пару раз, после чего мне пришлось перезагрузитьсяthumbs down.

На всякий случай вот фрагмент файла irbisc.ini, содержащий требуемую модификацию:

[USERMODE]
UMNUMB=2
UMDLL0=LAN_Export.dll
UMFUNCTION0=LANExport
UMPFT0=LAN
UMNAME0=Экспорт из ЛАНИ
UMGROUP0=2
UMICON0=

Файл LAN.pft состоит из одной строки: &unifor('+0')

Вложения: Плагины.rar (16.4KB)   Исходники LAN_Export2IRBIS.rar (195.7KB)   ExportDll.rar (62.8KB)  
Re: Пишем модуль для экспорта данных с сайта издательства "ЛАНЬ" как пример реализации плагина к ИРБИС64
Пользователь: Gena (IP-адрес скрыт)
Дата: 12, December, 2012 22:13

Очень интересно! Мне не приходилось сталкиваться с изданием Лань, но давно было интересно поработать с импортом данных из внешних источников. Как вариант можно рассматривать импорт данных с того же Озона и прочих книготоргующих ресурсов. Думаю не последнее место в таких разработках может занять поиск и импорт в уже имеющуюся запись обложек книг. Это как пожелание на будущее. Вообще проделанная работа очень впечатлила!

Re: Пишем модуль для экспорта данных с сайта издательства "ЛАНЬ" как пример реализации плагина к ИРБИС64
Пользователь: Lavrinovich (IP-адрес скрыт)
Дата: 14, December, 2012 06:16

Что с вашими предыдущими проектами? Особенно интересен библиоредактор. Если его пока не удалось реализовать полностью, нужно хотя бы обсудить замысел и обязательно - опыт предшественников.

irbis_arbat@mail.ru



Редактировано 3 раз. Последний раз 15.12.2012 07:15 пользователем Lavrinovich.

Re: Пишем модуль для экспорта данных с сайта издательства "ЛАНЬ" как пример реализации плагина к ИРБИС64
Пользователь: S-presso (IP-адрес скрыт)
Дата: 14, December, 2012 08:45

Скажем так, это не то, чтобы новый проект - просто я исследовал возможность интеграции своих модулей на C# в Каталогизатор на примере этого задания. Само задание в общем-то и не предусматривало импорт БО в Ирбис, просто от меня требовалось составить список изданий по определённой тематике, предлагаемых издательством ЛАНЬ. Ради этого меня даже отпустили домой, думали, я долго буду с этим возиться. Но я быстро сообразил, что к чему, весь день занимался своими делами, и лишь под вечер быстренько накатал необходимый модуль и с его помощью где-то за час-полтора всё сделал. Обидно, что другим, кому поручили эту работу, пришлось делать это копи-пастом. А так вообще мне по душе фриланс, поскольку результаты типичного рабочего дня у меня и у других, кто занимается у нас компьютерной обработкой, - это, как говорится, две большие разницы. Но ведь приходится же отсиживать свои часы! С фрилансом я бы мог хотя бы ориентироваться на объем выполняемой работы, а не на часы. Но разве такая форма сотрудничества предусмотрена нашим законодательством для бюджетной сферы...

В данной теме я просто хотел показать возможность того, как достаточно просто осуществить интеграцию в Ирбис книжных описаний с различных сайтов. Если у кого-то возникнет конкретная задача, то можно будет легко переделать предлагаемый проект. Тут в общем-то и особого знания C# не требуется, чтобы разобраться, - на Delphi будет сделать подобный плагин для Каталогизатора даже проще. Хотя, если вы привыкли к C-образным языкам, тут сложнее в плане пользовательских разработок для Ирбиса. Впрочем, существует C++ Builder, который позволяет делать всё то же, что и Delphi, и даже больше. Вот только компонентов для него к сожалению, не так много (а дельфийские компоненты, по крайней мере для старых версий компилятора и среды, совместимы только на уровне исходных текстов).

Что касается предыдущих проектов, то я как раз рассматриваю возможность их переписывания на C++ Builder с непосредственным подключением к Каталогизатору. Ведь кроме сложности интеграции с Ирбисом меня не совсем устраивает в разработке под .NET и то, что исходный код бинарника весь как на ладони.

Re: Пишем модуль для экспорта данных с сайта издательства "ЛАНЬ" как пример реализации плагина к ИРБИС64
Пользователь: Lavrinovich (IP-адрес скрыт)
Дата: 17, December, 2012 12:20

Видимо, имеет смысл для вузов и если продукция данного издательства составляет большой процент новых поступлений. Какой именно примерно?

irbis_arbat@mail.ru

Re: Пишем модуль для экспорта данных с сайта издательства "ЛАНЬ" как пример реализации плагина к ИРБИС64
Пользователь: S-presso (IP-адрес скрыт)
Дата: 18, December, 2012 22:39

Цитата:
Lavrinovich
Особенно интересен библиоредактор. Если его пока не удалось реализовать полностью, нужно хотя бы обсудить замысел и обязательно - опыт предшественников.

Насчёт библиоредактора... Тут встаёт проблема с реализацией. Если делать как плагин - надо решить описанную мной (см. также ниже) проблему; если как самостоятельное приложение, наверное, достаточно будет экспорта записей в файл, которые может подхватить IRBIS64 - как моё первое приложение для Ирбиса, выложенное здесь: [irbis.gpntb.ru]. Но кому-то такой экспорт-импорт может показаться сложным, поскольку требует многократных манипуляций с мышкой (мне вот именно по этой причине не нравится реализация нового режима печати карточек).



Редактировано 1 раз. Последний раз 28.12.2012 17:24 пользователем S-presso.

Re: Пишем модуль для экспорта данных с сайта издательства "ЛАНЬ" как пример реализации плагина к ИРБИС64
Пользователь: Lavrinovich (IP-адрес скрыт)
Дата: 19, December, 2012 10:41

Все-таки интеграция с браузером. Но у вас в фонде есть или были ноты, наверно есть и АВ-документы. Отсюда идея библиобраузера-медиаплейера. Прообраз: CD-ROM-энциклопедия Microsoft Encarta, в ней, например, статья о композиторе + портрет + рукопись + аудиофрагмент самого популярного произведения. Были и просто роскошные очень содержательные научно-популярные диски Multimedia Beethoven, Multimedia Stravinsky... с викторинами в конце... то есть диск-книга-познавательная игра...
Или был такой СD-учебник "Интернет для библиотекарей" Таньки Мошковской в неудобной имхо оболочке Adobe Acrobat.
"Электронный книгофильм" (И.Ефремов, Туманность Андромеды, 1957 г.)
Другой пример. Википедия может со временем стать справочной ЭБ: статьи о "персонах" имеют ссылки на "полнотексты", сочинения самой "персоны" и о ней, но не всегда и обычно только от 1 до 3.
В перспективе вырисовывается полная интеграция, слияние фонда и каталога. До сих была только в названии кафедры фондов и каталогов;)
ЗЫ. Координаты "Лани" [irbis.gpntb.ru]

irbis_arbat@mail.ru



Редактировано 4 раз. Последний раз 23.12.2012 09:11 пользователем Lavrinovich.

Re: Пишем модуль для экспорта данных с сайта издательства "ЛАНЬ" как пример реализации плагина к ИРБИС64
Пользователь: S-presso (IP-адрес скрыт)
Дата: 28, December, 2012 17:34

Цитата:
Gena
Очень интересно! Мне не приходилось сталкиваться с изданием Лань, но давно было интересно поработать с импортом данных из внешних источников. Как вариант можно рассматривать импорт данных с того же Озона и прочих книготоргующих ресурсов. Думаю не последнее место в таких разработках может занять поиск и импорт в уже имеющуюся запись обложек книг. Это как пожелание на будущее. Вообще проделанная работа очень впечатлила!

И всё-таки не могу отделаться от мысли, что поддержка плагинов в Ирбис реализована ещё слишком слабо для того, чтобы создавать с их помощью серьёзные приложения. Или они нормально работают только на Delphi (но это очень странно)? Переубедите меня, если я не прав. Мне вот никак не удавалось дома на виртуальной машине воспроизвести условия, при которых мои плагины работали, а сегодня с ноутбука удалось в Каталогизаторе загрузить модуль распознавания библиографического описания. Но срабатывал он только один раз, причём (ВНИМАНИЕ!) только, если перед этим запускался описываемый здесь модуль для ЛАНИ (достаточно было просто вызвать его окно и сразу же его закрыть). Чудеса, да и только! Странные вещи происходят, если работу Каталогизатора пришлось завершить аварийно, если он не смог выйти из пользовательского режима и нормально запустить плагин. Я повозился немного, скармливая Ирбису различные версии своих DLL и внося соответствующие изменения в IRBISC.INI, но понять логику его работы так и не смог. С изменением одного плагина почему-то перестают работать и другие плагины с тем же именем, но расположенные в других папках. Причём срабатывали даже старые, уже перезаписанные DLL-ки - кэширует он их, что ли? Не работают совершенно верные настройки файла инициализации - только после того, как я их заменил на заведомо неработающие и запустил Каталогизатор и из него - плагин (с ожидаемой ошибкой, потребовавшей аварийного выхода из программы), а затем вернул всё, как было, - мой плагин для БО снова заработал. Здравый смысл подсказывает, что где-то происходит утечка памяти. Моя догадка такова: плагины, написанные для .NET, могут отказываться повторно запускаться, поскольку пользователь закрывает их прежде, чем успевает запуститься сборщик мусора, и какие-то процессы остаются висеть в памяти.



Извините, только зарегистрированные пользователи могут писать в этом форуме.
This forum powered by Phorum.