C++ (ATL) против METTLER-TOLEDO
Стараясь быть кратким, но понятным сообщу, что потребовалось как-то мне заставить работать весы знаменитой фирмы «Mettler-Toledo» с 1С Предприятием 8.1 … Вариантов особых не было интерфейс (RS-232) и работа с COM портом. На весах взвешивают партии слитков из драгметалла. Компьютер, который планировалось задействовать для этой цели, не имел физических COM портов, но ситуацию спас преобразователь интерфейса USB<->COM. Кстати, стоимость 2500 руб. Не так уж и много…
Чтобы не переносить данные из одной программы в другую (Ну это я о способе реализации), было принято решение выгружать полученный вес прямёхонько в 1С. Для этого будем писать внешнюю компоненту, в которой и реализуем весь функционал работы с последовательным портом, обработку команд весов, а надо сказать, командная строка этих METTLER довольно многообразна и обратную связь с 1С!
В результате этой разработки появилась универсальная .dll, которая позволяет в принципе работать с любым устройством , у которого есть возможность подключиться на последовательный порт и что либо туда писать. А также обработка для подключения внешней компоненты и управления настройками COM порта…
Я уже видел как некоторые товарищи использовали bat файлы чтобы имитировать устройство на линии. Что сказать?! Это их право . Зачем делать сложным то, что проще простого? Для начала просто поставим перемычку на 2-3 контакты, так мы сможем читать то, что сами отправили в порт… Для первичной отладки сойдет! А вообще я использовал модем, ну кто мне даст весы стоимостью 300 тыс. руб.? Модем на моём ноутбуке прекрасно заменил оконечное устройство! Команда «wat» неизменно возвращала отклик «ОК!», «wat it» возвращала ответ Toshiba Software XXX.XX, где крестики модель устройства и код прошивки. ATDP XXX-XX-XX (крестики номер телефона) заставляла модем резво набирать предложенный номер! Любые данные записанные мной в порт и не распознанные модемом как команда отсылались обратно эхом!
Теперь некоторые замечания о внутреннем устройстве компоненты, написанной с использованием технологии СОМ. За основу был взят мой собственный шаблон, вернее правленый мной до рабочего состояния с диска ИТС и выложенный на известном всем ресурсе www.nowa.cc , кстати по просьбе трудящихся совсем недавно он был обновлён. Кроме основного потока, создается поток чтения и находится в режиме ожидания события поступления в порт данных от устройства, а так же при записи команды в порт, создается поток записи, но этот сразу завершается после операции записи. То есть вы уже наверняка поняли, что мы используем асинхронные операции чтения и записи! Это позволяет сделать наше приложение очень быстрым и не загружать процессор бессмысленной работой…
Лишь некоторые замечания по реализации кода «Внешнего события». Я обещал быть краток ! Думаю у новичков вызовет затруднение один вопрос. А именно как реализовать в своем коде вызов внешнего события?! (если всё сделано правильно, 1С обязательно вызовет свои обработчики, уж поверьте…) Так вот, при инициализации компоненты обязательно присвойте значению глобального указателя на IAsynchEvent объявленного со спецификатором
// Это глобальный указатель для реализации событий в файле AddIn.cpp
static IAsyncEvent *pAsyncEvent = NULL;
значение параметра m_iAsyncEvent функции QueryInterface,
m_iAsyncEvent = NULL;
pConnection->QueryInterface(IID_IAsyncEvent,(void **)&m_iAsyncEvent);
pAsyncEvent = m_iAsyncEvent;
далее в этом же классе объявите public функцию в которой через глобальный указатель, которому вы только что присвоили значение вызовите метод ВнешнееСобытие. Примерно так
void CAddIn::Event(BSTR Sourse, BSTR Message, BSTR Data)
{
pAsyncEvent->ExternalEvent(Sourse, Message, Data);
}
Дальше в своем классе (у меня в шаблоне он MyClass) объявите указатель на класс где вы присваивали значение глобальному указателю и добавляли функцию с вызовом обработчика внешнего события.
CAddIn* pAddIn;
Обязательно указатель, не пытайтесь создать объект не получится! Так как класс абстрактный, т.е. не все чистые виртуальные функции переопределены и реализованы! Не забудьте добавить в заголовочный файл своего класса заголовок класса на который мы объявляем указатель. Ну всё теперь в своем классе вы можете вызывать функцию абстрактного класса, передав ей нужные параметры, которая в свою очередь вызовет обработчик внешнего события в 1С!
После того как порт открыт установятся таймауты с такими значениями если вам это не подходит выберите нужные на вкладке настройка!
CommTimeouts.ReadIntervalTimeout = MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadTotalTimeoutConstant = 0;
CommTimeouts.WriteTotalTimeoutMultiplier = 0;
CommTimeouts.WriteTotalTimeoutConstant = 0;
Важно: Перед тем как закрыть 1С убедитесь, что закрыли порт!!! Или хотя бы обработку, в этом случае она сама попробует закрыть порт… В противном случае реализуйте механизм закрытия порта при завершении работы системы или соответствующую проверку!
Предлагаемая внешняя обработка не является законченным решением и предназначена для демонстрации возможностей внешней компоненты.
P.S. Вот уже почти год как я занимаюсь разработкой и внедрением программного комплекса на базе 1С 8.1 Бухгалтерии, специфика учета оборота драгоценных металлов заставила реализовать невероятные схемы от которых по началу становилось просто муторно . Что-то удалось сразу и не требовало никаких доработок. Например, прием и обработка сырья. А вот бизнес процесс, который охватывает собой практически весь производственный цикл и сданный мной в работу ещё месяца три назад оказался слишком сложен для понимания операторов, не смогли освоить! И это явный промах . К чему это я? Да просто всё… накопился ценный опыт работы в отрасли переработки драгметаллов, разумеется в сфере автоматизации документооборота и IT технологий! И я готов предложить его заинтересованным производственникам.