COM-Объект для работы с Web-камерой в 1С

В этой статье я расскажу как можно сделать свой собственный COM-объект на примере работы с веб-камерой, который можно будет использовать в 1С.

Почему именно для вебки? Такова была моя реальная задача на работе. И я хочу поделиться опытом, как это можно реализовать.

Собственно задача, а точнее подсистема, которую мне нужно было реализовать: фотографировать сотрудников и посетителей и сохранять фото в 1С и во внешней среде СКУД Gate-IP. Т.к. оболчка этой СКУД очень «СКУДна», а точнее не «юзабельна» для сотрудников службы безопасности, да и просто для рядового пользователя, то руководством было принято решение сделать некую оболочку в среде 1С на «Тонких» формах 🙂

Перекопал весь интернет в поисках какой-нибудь внешней компоненты для работы с веб-камерой. К сожалению, не нашел ничего полезного или работающего на Windows 10 и Windows 7.

Нет. Конечно кое-что нашел и рабочее, но реализованное в виде компоненты ActiveX, которую сложно прикрутить к управляемым формам.

Один хороший человек под ником Душелов (светлая память ему!!! говорят, что был отличным программистом 1С и не только 1С. Он погиб в автокатастрофе 🙁 🙁 🙁 ) опубликовал статью http://infostart.ru/public/16446/ в которой собственно и выложил свою компоненту ActiveX, написанную цать лет назад для 7.7. К сожалению, исходников его компоненты я не нашел. Прикрутить её получилось на Обычных формах. Трансляция в форму 1С работает. Но не сохраняет картинку. Понять причину не удалось, но возможно всё дело в винде 10ке 🙁 Пробовал прикрутить её в Управляемые формы, используя как COM-объект. Опять же — запускается, но не фоткает. Этот способ Душелова собственно и вдохновил меня на написание собственного COM-объекта.

Когда искал — всюду натыкался на некую библиотеку AviCap (сокр. от AVI Capture). Эта библиотека, а точнее форма (диалоговое окно) Windows для работы с веб-камерой, которое запечатано в avicap32.dll и лежит в папочке Windows\System32. Библиотека должна быть даже в древних XPюшках и возможно 98х.

Удобная штука, т.к. не нужно ставить никаких драйверов и стороних софтин для веб-камеры. Просто «ваткнул» и поехал.

Используя эту библиотеку, можно вызвать окно вебки скрытым или видимым и посылать этому окну такие команды, как:

  • подключиться к вебке
  • сделать стоп-кадр (сфотографировать)
  • сохранить этот стоп-кадр в буфер обмена или в файл
  • отключиться от вебки
  • и многое другое полезное.

Пробовал напрямую дергать методы этой dll’ки из 1С, но увы — бесполезно. Может мой level в 1С не достаточно высок 🙂

Покурил в интернетах о том, как же написать свою внешнюю компоненту для 1С и наткнулся на статью всё там же на Инфостарте http://infostart.ru/public/151246/. Имея опыт кодера на C и небольшой опыт на C# — решить эту проблему было не сложно.

И так….

Запускаем среду Visual Studio (у меня 2015 «лицензионная») .Безымянный

Создаем новый проект Visual C# -> Библиотека классов.

Как и в статье, удаляем нафиг весь код.

И пишем (кому лень, сырцы выложу в конце статьи):

Далее ищем guidgen.exe там, где установлена Visual Stuido. (З.ы. Можно искать прямо из корня диска C:) Запускаем. И ставим пункт 5 (на Инфостарте пример на старой среде Visual Studio, но не важно).

Безымянный1

Жмем Создать GUID до тех пор, пока нам не понравится GUID. Шутка 🙂

Жмем Копировать. И вставляем в код, чтобы модуль выглядел примерно следующим образом.

Далее буду копировать текст с Инфостарта со своим кодом.

Определим интерфейс для COM-событий(новый GUID получаем с помощью утилиты guidgen.exe)

Описываем класс реализующий интерфейсы(новый GUID получаем с помощью утилиты guidgen.exe)

Вот так мы описали пространство имен и класс нашего будущего COM-объекта. Чего-то в нем не хватает. Ах да. Методов (процедур, функций, которые мы будем дергать, например из 1С). Устал? Нет? Тогда let’s go.

В своем примере я описал такие методы:

  • функция OpenWindow(Caption, x, y, w, h) (открывает (создает) окошко с видеопотоком вебки).
    Возвращает Handle окна. Что это? Расскажу своими словами как я это понимаю. Каждое открытое окно, каждый элемент управления на открытой форме в среде Windows имеет свой Handle — числовой код, номер. Что-то вроде Ссылки в 1С. Идентифицирует открытые окна на твоем экране. По этому Хэндлу ты можешь обратиться к этому окну (или элементу управления) с помощью функций WinApi и например, жмакнуть программно кнопку, или получить текст из поля ввода, или закрыть окно. Даже можно нарисовать свой собственный элемент управления в чужой форме. Круто? Да. Но моя статья не об этом.
    Параметры функции думаю понятны. Caption — заголовок окна (строка), x, y, w, h — координаты окна на экране и размеры (числа).
  • Функция SavePic(int _hWndC, string filepath). Сохраняет изображение (стоп-кадр) в файл filepath. Первым параметром передаем тот же Handle окна, который мы получили с помощью функции OpenWindow (для чего? расскажу далее).
  • Процедура HideWindow(int _hWndC). Прячет окно вебки (не закрывает его!!!). Параметром передаем Handle окна.
  • Процедура ShowWindow(int _hWndC). Показывает окно вебки, которое мы спрятали с помощью функции HideWindow.  Параметром передаем Handle окна.
  • Процедура CloseWindow(int _hWndC). Закрывает наше окошко вебки («убивает» его).
  • Функция ConvertPic(string FromFile, string ToFile). Преобразует изображения из одного формата в другой. Из какого формата в какой она определяет по расширениям файлов. (Добавлено 10.03.2017)

Для чего я сделал так много методов ? Да потому, что использую этот COM-объект в 1С на Управляемых формах на клиенте. Не нашел способа в 1С передавать созданный COM-объект между клиентскими процедурами и событиями 1С. По-этому решил хранить в 1С в реквизите формы не COM-объект, а Handle окна, которое мы создаем с помощью функции OpenWindow.

А для чего нужно было делать HideWindow и ShowWindow? Можно и без них. Первоначально получился COM-объект, который создает окно вебки, но не показывает его. По кнопке в 1С сохраняет картинку и показывает на форме 1С. Оказалось не удобно, т.к. получается в слепую нужно прицелиться вебкой на фэйс физлица и нажимать кнопку «Сфотографировать» до тех пор, пока не получится удачный кадр. По-этому и созрела мысль сделать некий прицел — открывается форма вебки, в которой мы видим видеопоток (изображение с веб-камеры) и жмем кнопку «Сфотографировать». По нажатию этой кнопки прячется форма вебки (HideWindow). В случае, если решили перефоткать опять нажимаем эту кнопку и отображается форма вебки (ShowWindow). Фуууух. Надеюсь понятно объяснил, т.к. сам в шоке от того что пишу 🙂

Функция ConvertPic необходима для того чтобы перегнать полученный кадр из формата BMP (Bitmap) в формат JPG (JPEG). Также она оказалась полезной не только при работе с вебкой, а например просто для загрузки/выгрузки изображения из/в любой формат. Сама 1С не умеет перегонять картинки в формат JPEG, а только в BMP (а может и ещё в какие-то, не вникал) и это печально 🙁 (Добавлено 10.03.2017)

В полном листинге присутствуют описания функций CreateWindowEx и DrawFrameControl. Я их закомментировал. Этими функциями я хотел нарисовать собственную кнопку в чужом окне (окно веб-камеры, не является родным окном 1С). Роль этой кнопки — фотографирование и оповещение 1Ске откуда забрать файл с кадром. Но увы — не взлетело 🙁 Развивать не стал. Может у тебя получится 😉 З.ы. если получится, буду признателен за сырцы, которые ты мне вышлешь на birgom собака birgom точка ru.

Продолжим….

Опишем в нашем классе процедуры и функции из внешних библиотек.

Этот код должен быть между скобочками {} в public classe MyClass:IMyClass

Первая функция capCreateCaptureWindowA из библиотеки avicap32.dll собственно и создает окошко вебки (окно видеозахвата).

SendMessage из user32 — универсальная функция WinApi, которая посылает сообщение с номером Msg окну с хэндлом hWnd и два произвольных параметра wParam и lParam (приведенных к числам. Например адрес памяти, где лежит массив или структура). Если в кратце, то у любого окна (или элемента формы) есть стандартные и определенные пользователем события на определенные сообщения Msg. В качестве параметров в эти события передаются wParam и lParam. Посылая сообщения определенному окну (элементу) мы как бы говорим — обработай команду Msg и вот тебе два параметра wParam и lParam (в них может передаваться что угодно). Понятно? Нет? — Кури WinApi. Функция может возвращать что угодно, например булево Истина — 1, Ложь — 0.

SetWindowPos из user32 — задает положение окна. Параметры должны быть понятны, кроме wFlags. ХЗ что это за параметр (какие-то флаги). Особо не вникал. См. WinApi

ShowWindowAsync из user32 — показывает или прячет окно. А точнее управляет видимостью окна.
Далее привожу полный листинг:

Все. С кодом справились. Осталось настроить проект.

На вкладке Сборка ставим галочку «Регистрация для COM-взаимодействия». Кстати, после окончательной сборки она снимается автоматически. Так и должно быть. Ставить её повторно не нужно!

Переходим на вкладку Подписывание.

Выбираем Создать, там где написано Выберите файл ключа строгого имени. Пароль на файл задавать не обязательно. В итоге должно получиться в этом поле SoyuzWebCam.snk.

Чуть не забыл. Переходим на вкладку Приложение и меняем версию .NET Framework на 2.0. Выше ставить нет необходимости, т.к. используемые библиотеки и весь проект вполне довольны версией 2.0 (установлено опытным путем). При создании нового проекта по умолчанию ставится последняя версия. Есть сомнения по-поводу того, нужна ли проекту .NET Framework, но увы — возможность отключить не нашел, да и не искал.

Переходим в файл AssemblyInfo.cs, нажимая два раза на нем в обозревателе решений.

И вставляем следующие две строки (выделены цветом):

Следующие два пункта добавлены 10.03.2017.
Они необходимы для работы функции ConvertPic, т.к. тип Bitmap из библиотеки System.Drawing, а перечисление ImageFormat.* из библиотеки System.Drawing.Imaging (которая включена в библиотеку System.Drawing).
В обозревателе решений правой кнопкой мыши по пункту Ссылки и выбираем из меню «Добавить ссылку…».

Далее на вкладке Сборки, Платформа ищем в списке System.Drawing, ставим галку и нажимаем Ок.

Все. Компилируем проект. Если все правильно сделали, то на выходе должна получиться dll’ка. Лежит она в папке Документы\Visual Studio 2015\Projects\SoyuzWebCam\SoyuzWebCam\bin\Release.

Чтобы установить компоненту необходимо запустить консоль от Администратора. Создаем ярлык на рабочем столе и в качестве пути к файлу пишем cmd.exe. Далее жмем правой кнопкой мыши на ярлыке и выбираем пункт «Запуск от имени администратора».

Выполняем команду cd C:\Windows\Microsoft.NET\Framework\v2.0.50727

Для удобства можно положить скомпилированную dll’ку в корень диска C.

Далее выполняем команду regasm.exe «c:\SoyuzWebCam.dll» /codebase

Если видим сообщение «Типы успешно зарегистрированы» значит все ОК — COM-объект зарегистрирован.

У Душелова например, написан готовый bat’ник (файл с расширением bat), который я немного изменил:

Запускаем его также от администратора (правой кнопкой мыши по нему ;)).

Что он делает: копирует файл dll в папку Windows и регистрирует её.

Всю папку проекта (вместе с скомпилированным файлом) завернул в архив и положил сюда.

А папку с «установщиком» завернул сюда.

Как пользоваться «установщиком»: распаковываем SoyuzWebCam_COM.rar в папку корень диска С, чтобы dll’ка была доступна по следующему пути c:\SoyuzWebCam_COM\SoyuzWebCam.dll. Запускаем от Администратора reg.bat.

Фууух. Самое сложное сделали.

Переходим к 1Ске.

Сложного тут мало.

Приведу сразу полный листинг общей формы, которая вызывается как форма выбора.

Всё! Надеюсь, что кому-нибудь пригодится. Предложения и критику пишите в комментарии или мне на почту birgom собака birgom точка ru.

Ещё раз: проект C# лежит здесь, а «установщик» здесь

17 thoughts on “COM-Объект для работы с Web-камерой в 1С”

  1. Подскажи пожалуйста, не могу понять, есть 10 клиентских ПК, везде Windows 10, все подключаются к серверу 1C через RDP, на всех включен проброс камер через RemoteFX.
    На пяти компах из десяти, 1С при открытии окна захвата изображения с камеры выдаёт пустой чёрный квадрат, хотя на остальных пяти ПК всё в норме, обновления все стоят, ПО везде лицензионное, все ПК в одной сети.

    В чём может быть причина?

    Стороннее ПО видит картинку с камер на всех ПК.

    1. Для начала попробуй будет ли работать в стандартном приложении Камера (меню Пуск и прям там набираешь Камера), т.к. стороннее ПО может использовать свои библиотеки, дровишки, а я использую драйвер по умолчанию и стандартную библиотеку avicap32.dll. Если стандартная не будет работать, то возможно avicap32.dll «не рабочий». Попробуй тогда заменить его с тех машин, на которых работает.

      И ещё, я использую (если память не изменяет) 32-битную версию avicap32.dll, а есть ещё 64-битная — лежит в (C:\Windows\SysWOW64), хотя точно не уверен по поводу её битности.

      Пробуй камеры перетыкать с рабочих на не рабочие, возможно в драйверах дело 🙂
      К сожалению, больше нечем помочь, т.к. у меня заработало так и я не углублялся особо в дебри.

      Напиши тогда здесь, как решил проблему 😉

      1. Ещё может быть вот в этом дело:
        SendMessage(hWndC, WM_CAP_DRIVER_CONNECT, 0, 0);
        SendMessage(hWndC, WM_CAP_DRIVER_CONNECT, 0, 0);

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

  2. на сервере нет встроенного приложения — камера,
    но установив на сервер SKYPE и утилиту AMCAP понял, они получают картинку великолепно!
    http://www.noeld.com/dl.asp?filename=AMCapSetup.exe

    можно ли как-то доработать? готов оплатить затраченное время))))

    заранее спасибо!

    1. Попробуй драйверы установить, сменить или вовсе удалить (если стоят). Без дров многие камеры работают на стандартном драйвере виндовс. Попробуй без удаленки и без драйверов на машине с 1С завести — возможно RemoteFX пробрасывает как-то криво.
      К сожалению, сейчас особо нет лишнего времени. Да и воспроизвести как? По удаленке? + Камеру нужно.
      Не проще ли купить другие камеры, а эти вернуть или продать на авито? У меня работает с камерами Logitech HD Webcam C270, цена в районе 1200 руб.

  3. Огромное спасибо, несколько дней интернет лопатил, ничего похожего не нашел, а здесь — то, что нужно!

  4. Спасибо.
    Работает.
    Но на ноутбуке где две камеры ,просто показывает черное окно, а камера при этом горит.

    Можно ли как то в коде 1С указать какую именно камеру брать?
    Может это поможет.

    1. Спасибо, что пользуетесь!
      Планирую добавить вопросы по 1С Профессионал по технологическим вопросам

  5. Добрый день. Такой вопрос.
    Делаю следующее.
    comobject = Новый COMОбъект(«SoyuzWebCam.MyClass»);
    comobject.ShowWindow(ИДОкнаКамеры);
    comobject.SavePic(ИДОкнаКамеры, ПутьКФайлу)
    comobject.HideWindow(ИДОкнаКамеры);
    Фото делается, но изображение всегда одно — то которое было в момент первого открытия окна. Тоже самое получается если окно постоянно держать скрытым. Не смогли побороть такое поведение?

    1. Добрый день, Сергей.

      Что возвращает comobject.SavePic(ИДОкнаКамеры, ПутьКФайлу)? Истину / Ложь? Возможно файл занят другим экземпляром объекта (первым вызовом SavePic).
      comobject = Неопределено делаете?
      Если не поможет и при этом файл занят, то попробуйте ещё ПутьКФайлу всегда новый получать.

      Трудно судить в чем особенность. Вот если бы Вы привели полный листинг работы с этим com объектом.

      1. SavePic — возвращает истину. И файл новый создается. Но изображение всегда одно и тоже — то, которое было в момент вызова OpenWindow. Неопределено не делаю т.к. весь код вынесен в общий модуль и comobject — создается локально.
        И путь к файлу всегда разный.

        Код общего модуля.
        функция ПередНачаломРаботы(Заголовок, X, Y, W, H) Экспорт
        comobject = Новый COMОбъект(«SoyuzWebCam.MyClass»);
        hWndC = comobject.OpenWindow(Заголовок, X, Y, W, H);
        Возврат hWndC;
        КонецФункции

        Функция СделатьФото(ИДОкнаКамеры, ПутьКФайлу) Экспорт
        comobject = Новый COMОбъект(«SoyuzWebCam.MyClass»);
        Если НЕ comobject.SavePic(ИДОкнаКамеры, ПутьКФайлу) Тогда
        Возврат Ложь;
        КонецЕсли;
        Возврат Истина;
        КонецФункции

        Процедура СпрятатьОкноКамеры(ИДОкнаКамеры) Экспорт
        comobject = Новый COMОбъект(«SoyuzWebCam.MyClass»);
        comobject.HideWindow(ИДОкнаКамеры);
        КонецПроцедуры

        Процедура ПоказатьОкноКамеры(ИДОкнаКамеры) Экспорт
        comobject = Новый COMОбъект(«SoyuzWebCam.MyClass»);
        comobject.ShowWindow(ИДОкнаКамеры);
        КонецПроцедуры

        Код в модуле формы.
        &НаКлиенте
        Процедура ПриОткрытии(Отказ)

        Попытка
        Объект.ИДОкнаКамеры = МодульРаботыСКамерой.ПередНачаломРаботы(«»,0,0,10,10);
        МодульРаботыСКамерой.СпрятатьОкноКамеры(Объект.ИДОкнаКамеры);
        Исключение
        Объект.ИДОкнаКамеры = Неопределено;
        КонецПопытки;

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

        &НаКлиенте
        Процедура ПолучитьФотоКлиента(Тип)

        МодульРаботыСКамерой.ПоказатьОкноКамеры(Объект.ИДОкнаКамеры);
        Рез = МодульРаботыСКамерой.СделатьФото(Объект.ИДОкнаКамеры, Объект.АдресСохраненияФото + «\»+Формат(ТекущаяДата(), «ДФ=dd_MM_yyyy_HH_mm_ss»)+»_»+Тип+».jpg»);
        МодульРаботыСКамерой.СпрятатьОкноКамеры(Объект.ИДОкнаКамеры);

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

Добавить комментарий

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