Компилирование внешней компоненты AddInNative в ОС Linux

В статье отражены некоторые моменты, которые нужно учесть, чтобы скомпилировать пример 1С-вской внешней компоненты AddInNative в ОС Linux.

Решил посмотреть, как работает внешняя компонента для 1С в Linux-е, благо под рукой уже была настроенная виртуалка с Xubuntu и установленной там платформой 8.3.5.1383.

Скопировал в виртуалку с диска ИТС папку VNCOMP83/example/NativeAPI/, зашёл в эту папку, набрал команду «make» и:

$ make

In file included from AddInNative.cpp:15:0:
AddInNative.h:4:27: фатальная ошибка: ComponentBase.h: Нет такого файла или каталога
компиляция прервана.
make: *** [AddInNative.o] Ошибка 1

Посмотрел, где расположен файл ComponentBase.h — как оказалось, он (и ряд других заголовочных файлов) находится в папке VNCOMP83/include/.

Вывод 1: с диска ИТС нужно копировать 2 папки — VNCOMP83/example/NativeAPI/ и VNCOMP83/include/

Пробую скомпилировать ещё раз:

$ make

In file included from AddInNative.cpp:15:0:
AddInNative.h:73:5: ошибка: «HANDLE» не является именем типа
AddInNative.h:74:5: ошибка: «HANDLE» не является именем типа

make: *** [AddInNative.o] Ошибка 1

Действительно, в файле AddInNative.h в самом конце присутствуют следующие определения:

    HANDLE              m_hTimer;
    HANDLE              m_hTimerQueue;

Linux про тип HANDLE ничего не знает. Смотрю где используются m_hTimer и m_hTimerQueue — они используются в файле AddInNative.cpp — один раз в CAddInNative::CAddInNative(), ещё один раз в CAddInNative::Done() и, наконец, в CAddInNative::CallAsProc(…) в ветках «case eMethStartTimer» и «case eMethStopTimer». Причём в последней процедуре код, связанный с этими переменными, выделен как Windows-специфичный (#ifndef __linux__ … #endif). Отсюда можно сделать вывод, что в других местах разработчики просто забыли выделить код с помощью директив. Сделаем это самостоятельно.

В AddInNative.h меняю:

    HANDLE              m_hTimer;
    HANDLE              m_hTimerQueue;

на

#ifndef __linux__
    HANDLE              m_hTimer;
    HANDLE              m_hTimerQueue;
#endif

В AddInNative.cpp меняю:

CAddInNative::CAddInNative()
{
    m_iMemory = 0;
    m_iConnect = 0;
    m_hTimerQueue = 0;
}

на

CAddInNative::CAddInNative()
{
    m_iMemory = 0;
    m_iConnect = 0;
#ifndef __linux__
    m_hTimerQueue = 0;
#endif
}

после чего

void CAddInNative::Done()
{
    if(m_hTimerQueue )
    {
        DeleteTimerQueue(m_hTimerQueue);
        m_hTimerQueue = 0;
    }
}

меняю на

void CAddInNative::Done()
{
#ifndef __linux__
    if(m_hTimerQueue )
    {
        DeleteTimerQueue(m_hTimerQueue);
        m_hTimerQueue = 0;
    }
#endif
}

Как вариант, можно просто закомментировать «linux-неугодный» код, но тогда исходники перестанут компилироваться под Windows.

Вывод 2: перед компилированием нужно убрать Windows-специфичный код из исходников.

Очередная попытка:

$ make

AddInNative.cpp:438:49: ошибка: нет подходящей функции для вызова «IMsgBox::Alert(const wchar_t [3])»

make: *** [AddInNative.o] Ошибка 1

Тут уже даже разбираться не хочется, поэтому просто в файле AddInNative.cpp в функции CAddInNative::CallAsProc() комментирую строки:

//                        if (succeed)
//                            imsgbox->Alert(L»OK»);
//                        else
//                            imsgbox->Alert(L»Cancel»);

Вывод 3: перед компилированием нужно убрать ещё кое-какой код.

И ещё раз:

$ CXXFLAGS=»-D __linux__» make

g++ -MM -D __linux__ -I../include -m32 -finput-charset=WINDOWS-1251 -fPIC AddInNative.cpp >  AddInNative.d
g++ -c  -D __linux__ -I../include -m32 -finput-charset=WINDOWS-1251 -fPIC dllmain.cpp -o dllmain.o
g++ -MM -D __linux__ -I../include -m32 -finput-charset=WINDOWS-1251 -fPIC dllmain.cpp >  dllmain.d
g++ -c  -D __linux__ -I../include -m32 -finput-charset=WINDOWS-1251 -fPIC stdafx.cpp -o stdafx.o
g++ -MM -D __linux__ -I../include -m32 -finput-charset=WINDOWS-1251 -fPIC stdafx.cpp >  stdafx.d
g++ -D __linux__ -I../include -m32 -finput-charset=WINDOWS-1251 -fPIC -shared AddInNative.o dllmain.o stdafx.o -o AddInNative.so -lpthread

Аллилуйя!!! Наконец-то, в каталоге появился долгожданный AddInNative.so!!!

Теперь попробую подключить эту внешнюю компоненту. Создаю новую внешнюю обработку, добавляю на форму команду Команда1 и пишу обработчик:

&НаСервере
Процедура Команда1НаСервере()

Ок = ПодключитьВнешнююКомпоненту("/путь/к/файлу/внешней/компонеты/AddInNative.so", "AddInNative", ТипВнешнейКомпоненты.Native);
Если НЕ Ок Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Ошибка подключения ВК!";
Сообщение.Сообщить();
Возврат;
КонецЕсли;

ОбъектВК = Новый("AddIn.AddInNative.AddInNativeExtension");
ДвДанные = ОбъектВК.ЗагрузитьКартинку("/usr/share/backgrounds/space-01.jpg");
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Прочитано байт: " + ДвДанные.Размер();
Сообщение.Сообщить();

КонецПроцедуры

&НаКлиенте
Процедура Команда1(Команда)

Команда1НаСервере();

КонецПроцедуры

И она таки вертится:

17 Comments

  1. webester

    (1)Очень ценное и нужное замечание, держите нас в курсе. Весь инфостарт испереживался, я сам как на иголках, нервы на пределе, обновляю страницу, каждые 15секунд, Внимание! Опасный момент! И да! Да дорогие друзья, kostyaomsk таки поставил плюс и оставил об этом комментарий. Как мы все долго этого ждали, этого бесполезного никому не нужного комментария «поставил +». И вот он наконец то! Спасибо тебе kostyaomsk за твой флуд ради флуда.

    Reply
  2. Yagodka.Andrey

    За статью спасибо, камрад.

    Сейчас компоненты забросил, но… чем черт не шутит )

    Reply
  3. q_i

    (4) Yagodka.Andrey, если будет интерес — можно будет попробовать скооперироваться.

    И вообще, если у кого-нибудь есть какая-нибудь практическая задача — пишите — может что-нибудь сделаем. А то сейчас у меня весь интерес чисто академический (единственный клиент с линуксовым сервером перешёл на винду ещё год назад). ))

    Reply
  4. vslimv

    (5) Давно мечтаю о telnet’e на сервере. Правда в ВК дуб)

    Но очень радостно, что подобные технологии развиваются, а то в моем окружении никто не решился на com в лине)

    Reply
  5. q_i

    (6) vslimv, ну на com в лине не решился даже microsoft ))

    А какую задачу хочется решить с помощь telnet’а на сервере?

    Reply
  6. pumbaE

    sleep, добавь sleep

    регулярки

    поддрежку webcosket , дабы можно было-бы в тонком клиенте прогресс бар нарисовать.

    rabbitmq

    Reply
  7. q_i

    (8) pumbaE,

    sleep:

    ЗапуститьПриложение(«sleep 5», , Истина);

    Регулярки аналогично через perl/grep.

    Вообще, есть мысль написать статью про вызов линуксовых команд из 1С. В простейшем варианте через ЗапуститьПриложение() с перенаправлением stdout во временный файл с последующим разгребанием этого файла средствами 1С. Но хочется ещё реализовать компоненту для работы без временного файла, т.е. вызывается команда и её stdout читается прямо в строку 1С (возможная опция — запись в stdin). В примитивном варианте это можно сделать в компоненте через popen(), в более продвинутом через pipe()/fork()/exec(). Собственно, и статья родилась когда решил попробовать реализовать эту простенькую задачку и начал компилить сырцы 1с. Впрочем, popen() чего-то не захотел тогда работать (fread() сразу же возвращал 0, а feof(), соответственно, 1).

    WebSocket и RabbitMQ — а что с ними делать? )))

    Reply
  8. servs

    (7) например для управления Asterisk используя AMI, нужен клиент telnet.

    Есть ROM-Asterisk-Native, но там закрытый код.

    Reply
  9. q_i

    (10) servs, я Пастернака не читал с Astetisk-ом не работал, но судя по http://xgu.ru/wiki/AMI там можно обойтись или встроенным телнет клиентом в связке с expect, или написать что надо на python (благо, биндинги, судя по всему, есть). А запускать опять же банально через ЗапуститьПриложение().

    Если есть конкретная задача, можем посмотреть варианты решения.

    Reply
  10. vslimv

    (10) servs, ROM-Asterisk-Native насколько я знаю виндовый, а для линукса есть только у мико(далеко не бесплатно+куча **рни в подарок)+ она работает через богопротивный AJAM.

    Reply
  11. vslimv

    (11)

    встроенным телнет клиентом в связке с expect

    Немного не понял))

    ЗапуститьПриложение() не канает. Нужно слушать события по telnet’у, причем желательно асинхронное поступление событий в 1с.

    Хотя может я просто Вас не понял)

    Reply
  12. jaroslav.h

    (1) kostyaomsk, сколько вам можно писать «ХВАТИТЬ ПИСАТЬ, ПОЧТИ В КАЖДОМ СООБЩЕНИИ СВОЕЙ БЕЗПОЛЕЗНЫЙ КОММЕНТАРИЙ?????!!!!!», вы по другому не умете зарабатывать $m? Взрослый мужик, а хитрун еще тот. Стыдно!

    Reply
  13. q_i

    (14) myr4ik07, во-первых, беСполезный, а во-вторых, для выяснения отношений есть ЛС, форум, обращение к модераторам и т.п.

    Это касается и (3)

    Надеюсь на Ваше понимание.

    Reply
  14. q_i

    (13) vslimv, это скорее я не понял. Т.е. нужно открыть сокет, слушать его, а полученные данные передавать в 1С? Так? А кто и что будет в этот сокет писать/читать с другой стороны (со стороны клиента)?

    Reply
  15. webester

    (15)А че ему можно писать че попало, а мне нельзя?

    А че это вы тут указываете, если:

    для выяснения отношений есть ЛС, форум, обращение к модераторам и т.п.

    я предлагаю вам воспользоваться вашим же советом.

    Reply
  16. vslimv

    (16) Все именно так.Со стороны сервера asterisk висит AMI(Asterisk Manager API). Будет отсылать тебе после авторизации, все события в текстовом виде. Более подробно о нем и на русском тут .

    Со стороны клиента ВК и события из нее)

    В общем задача ее принимать текст из 1С и отправлять в AMI и наоборот из AMI в 1С. Сама ничего уметь не должна, разве что отправлять в 1С ошибку при подключении к сокету, если таковая имеется.

    Reply
  17. q_i

    Проблема с Alert-ами заключалась в том, что в в include/AddInDefBase.h в прототипе метода ожидается WCHAR_T* (строка 2-хбайтовых символов), а передаётся wchar_t* (строка 4-хбайтовых символов; L»OK» — это 4-хбайтовые символы):

    virtual bool ADDIN_API Alert(const WCHAR_T* text)

    Поэтому нужно поменять

    if (succeed)
    imsgbox->Alert(L»OK»);
    else
    imsgbox->Alert(L»Cancel»);

    на

    WCHAR_T *msg = NULL;
    if (succeed)
    ::convToShortWchar(&msg, L»OK»);
    else
    ::convToShortWchar(&msg, L»Cancel»);
    imsgbox->Alert(msg);
    delete[] msg;
    
    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *