Платформа 1С:Предприятие сегодня установлена в каждой второй организации. Админы влюбились в эту систему за простоту администрирования и легкость развертывания. Программисты балдеют от возможности доработки/разработки конфигураций под конкретные нужды. Пользователи в восторге от продуманного и стандартизированного (среди продуктов 1С) интерфейса. А что представляет эта платформа для X-совместимого чела?
Статья опубликована в журнале «Хакер» №3 (134), март 2010. Соавтор — Александр Эккерт.
1С’ок много всяких есть
Я не знаю, имел ли ты опыт работы с платформами 1С:Предприятие, но, чтобы мы говорили с тобой на одном языке, рассмотрим вкратце основные понятия. Итак, для начала стоит усвоить, что все платформы 1С:Предприятие условно можно разделить на две большие группы: 7.7, 8.x. Как ты мог догадаться, название групп характеризует номер версии.
Версия 7.7 на сегодняшней день считается самой старой из поддерживаемых. Несмотря на старость и отстойность, платформа этой версии не теряет свою популярность и до сих пор многие предприятия юзают именно ее. Причин тому много. Одна из главных — трудность миграции на новые версии. Все особенно усложняется, если в компании используется не типовая конфигурация, а самописное решение. В таких случаях без отряда программистов не обойтись. Ну да ладно, нас эта проблема мало волнует, нам интересна обратная сторона медали.
В платформе 1С:Предприятие есть встроенный язык, посредством которого и выполняется доработка/разработка конфигурации (то есть программного решения). Так вот, в версии 7.7 этот язык убог и сотворить на нем что-то действительно хакерское практически нереально. Заметь, я сказал «практически». В реале же лазейка есть — использовать различные внешние компоненты. Внешняя компонента — это специально разработанная динамическая библиотека, которая может быть подгружена в адресное пространство платформы, после чего ее функции можно вызывать на встроенном языке. Разработка компонент — процесс не шибко сложный, он подробно описан в многочисленных мануалах, которых в инете пруд пруди. В качестве среды разработки таких компонент можно заюзать либо Delphi, либо тот же Visual C++. Рассматривать написание компоненты в рамках этой статьи мы не будем. Почему? Увы, данный способ слишком тяжел в эксплуатации с практической точки зрения. Если в системе твои права обрезаны по самые «не хочу», то подсунуть левую DLL вряд ли удастся. К тому же, если в своей библиотеке ты заюзаешь «полезные» WinAPI-функции, то даю 99% вероятности, что проактивная защита установленного антивируса будет вопить, как потерпевшая.
С линейкой платформ версий 8х все совсем иначе. Они обладают богатыми возможностями, а встроенный язык годится не только для манипулирования данными и построения отчетов. Но не стоит раньше времени облизываться и думать, что на платформе 1С:Предприятие 8х можно написать абсолютно любую программу и уж тем более вызывать полезные WinAPI-функции. Увы, пока этого сделать нельзя. «Что же тогда в нем хорошего?», — спросишь ты. А я отвечу: большая коллекция готовых к работе объектов. В том числе и «классы» для работы с такими вещами, как: FTP, HTTP, XML, SMTP, POP3 и т. д. Представляешь, что с их помощью возможно написать?
Зачем юзать именно 1С:Предприятие
Я понимаю тебя, мой друг. Тебе ничего не стоит взять и написать вирус, троян, сканер портов и другие полезные в хакерском деле программы на любом «нормальном» языке программирования. Зачем же заморачиваться с каким-то 1С? Отчасти это так, но рано или поздно может возникнуть ситуация, когда кроме 1С:Предприятия, заюзать ничего будет нельзя. Вот тебе типичный пример. Ты устроился на работу админом БД и доблестные системщики урезали твои права по максимуму: ни тебе полноценного инета, ни возможности запуска «не доверенных» приложений и т.д. Зато в отношении баз и платформы 1С:Предприятие — никаких ограничений. Выполнять бэкапы и по возможности пересылать их на удаленные сервера, управлять списком пользователей — типичные задачи администратора баз данных. А вот теперь представь, что большинство недостающих и привычных в жизни вещей ты сможешь закодить прямо на встроенном в 1С:Предприятие языке! Ничто не помешает тебе заграбастать бэкап ценной базы данных и благополучно залить его на какой-нибудь сервак в инете.

Наипростейший FTP-клиент

SMTP-клиент или фундамент спам-тулзы?
С чего начинается кодинг под 1С
Встроенный язык 1С:Предприятия внешне очень сильно отличается от привычных нам С#, Python, Delphi и т. д. Главное отличие в том, что приходится использовать русский синтаксис. Проблема на первый взгляд не сильно большая, но по первости мозг рвет капитально. К счастью, это недоразумение победить возможно. Разработчики платформы 1С:Предприятие не зря получают свои деньги — они продумали все наперед и снабдили свое детище английским вариантом синтаксиса. Ты можешь юзать любой понравившийся вариант. Мне привычнее писать «по-русски», поэтому все листинги в статье будут приведены на великом и могучем. Если тебе по душе традиционный английский вариант — то милости прошу к встроенной документации. В ней описаны все функции/операторы: как в английской, так и в русской версиях.
Основы синтаксиса
Если мне не изменяет память, в нашем журнале еще ни разу не рассматривали кодинг под 1С:Предприятие, поэтому перед тем, как перейти к рассмотрению вопросов разработки реальных приложений, нужно обязательно познакомиться с базовым синтаксисом.
Регистр
Встроенный язык в 1С:Предприятие не чувствителен к регистру. Ты можешь писать название операторов/переменных прописными или строчными буквами — все будет работать одинаково хорошо.
Переменные
Как и во многих языках программирования, переменные ты можешь объявлять по ходу пьесы. Никаких областей типа дельфийского var нет (если не считать ключевого слова «Перем» для объявления глобальных переменных). С типами переменных ситуация аналогичная. Указывать для переменной конкретный тип в момент ее определения не требуется. Он выбирается на основе содержимого переменной. Пример:
СтроковаяПеременная = "Hello, world!";
//Это строковая переменная
ЧисловаяПеременная = 0;
//А вот это числовая переменная
Массив = Новый Массив(); //Ну а это массив
Процедуры, функции
В 1С:Предприятии принято делить весь код на процедуры и функции. Определяются они стандартным образом:
//Процедура без параметров
Процедура ПримерПроцедуры()
КонецПроцедуры
//Процедура с параметрами
Процедура ПримерПроцедуры(Параметр1, Параметр2)
КонецПроцедуры
//Пример функции
Функция ПолучитьДиректорию(Параметр1, Параметр2)
Возврат Параметр1 + Параметр2;
КонецФункции

С 1С:Предприятие поставляется отличная справка
Циклы
Во встроенном языке реализовано несколько видов циклов. По синтаксису они не особо отличаются от оформления аналогичных циклов в других языках программирования. Взгляни на примеры:
//Цикл «Пока». Аналогичен циклу while..do
// в других языках
//Пример выведет цифры от 1 до 9 в окно
//служебных сообщений
Счетчик = 1;
Пока Счетчик <> 10 Цикл
Сообщить(Счетчик);
Счетчик = Счетчик +1;
КонецЦикла;
//Цикл «Для». Аналогичен циклу
//for..to..do в других языках
//Пример выведет цифры от 1 до 10 в окно
//служебных сообщений
Для Счетчик = 1 По 10 Цикл
Сообщить(Счетчик);
КонецЦикла;
//Цикл «Для Каждого». Аналогичен циклу
//foreach в других языках
//Пример демонстрирует перебор массива
Массив = Новый Массив(2);
Массив[0] = 1;
Массив[1] = 2;
Для Каждого Запись Из Массив Цикл
Сообщить(Запись);
КонецЦикла;
Условия
Без условных операторов далеко не уедешь, внимательно посмотри на то, как они описываются в 1С:Предприятии:
//Пример использования конструкции
//"Если..Тогда..Иначе|ИначеЕсли.
//Конструкция аналогична "IF..THEN..ELSE" в
//других языках.
Значение = 5;
Если (Значение = 1) Тогда
Сообщить("Первое условие");
ИначеЕсли (Значение = 2) Тогда
Сообщить("Второе условие");
Иначе
Сообщить("Третье условие");
КонецЕсли;
Классы
А нет их в 1С:Предприятии :). Если ты привык к использованию ООП-стиля, то знай, что сейчас с этим напряг. Во встроенном языке пока отсутствует поддержка определения своих собственных классов. Приходится довольствоваться процедурным подходом.
FTP-клиент
FTP-клиент — софтина очень полезная. Довольствуешься ограниченным доступом к инету, а из приложений лишь MS Office, да оснастки для работы с СУБД? Что же делать, если требуется вывести с рабочего компа полезные файлы (например, бэкапчик корпоративной базы)? Как вариант, можно залить все файлы на свой личный FTP-сервер. Во многих организациях админы серьезно ограничивают доступ к WWW, а такие протоколы, как FTP, POP3, SMTP, остаются полностью открытыми. На этом и попробуем сыграть. Дело за малым — написать FTP-клиент. Да не просто написать, а закодить на языке, совершенно не предназначенном для этой цели.

SMTP-клиент в действии
Итак, запускай 1С:Предприятие в режиме «Конфигуратор» и создавай новую обработку. Я не буду тебе расписывать, как работать с самой IDE, это выходит за рамки статьи. Всю необходимую инфу ты сможешь посмотреть в хелпе. Лучше сразу к коду.
В 1С:Предприятии для работы с протоколом FTP есть встроенный и полностью готовый к работе класс: FTPСоединение. Класс достаточно хорош и в нем реализованы все необходимые свойства и методы. Тут тебе и поддержка работы через PROXY-сервер, и закачка/передача файлов и т. д. Не буду ходить вокруг да около, а перейду к рассмотрению рабочего примера. Вот код, отвечающий за соединение и отправку произвольного файла:
FTP-клиент средствами 1С:Предприятия
ИмяПользователя = "Логин"; Пароль = ""; Сервер = "Имя сервера"; КаталогДляЗаписи = " папка для записи"; Попытка FTPСоединение = Новый FTPСоединение(Сервер, , ИмяПользователя, Пароль); FTPСоединение.УстановитьТекущийКаталог( КаталогДляЗаписи); Исключение Сообщить("При попытке соединения с FTP | сервером возникла ошибка!", СтатусСообщения.Важное); Сообщить(ОписаниеОшибки()); Возврат; КонецПопытки; Попытка FTPСоединение.Записать( ЭлементыФормы.пвПутьКФайлу.Значение, ЭлементыФормы.ПолеВвода1.Значение); Исключение Сообщить("Во время передачи файла возникла ошибка!", СтатусСообщения.Важное); Сообщить(ОписаниеОшибки()); КонецПопытки;
Установка соединения по FTP начинается с инициализации класса «FTPСоединение». В качестве параметров конструктору необходимо передать следующие параметры:
- Сервер — адрес FTP-сервера (обязательный)
- Порт — номер порта FTP-сервера (необязательный)
- ИмяПользователя — пользователь на FTP-сервере
- Пароль
- Прокси — объект, содержащий настройки PROXY-сервера (необязательный)
- ПассивноеСоединение — Тип соединения (необязательный)
Если инициализация пройдет успешно, то FTP-соединение будет установлено. Ну а после его установки ты можешь воспользоваться одним из методов класса. Например, в своем примере я вызвал УстановитьТекущийКаталог(). Для демонстрации работоспособности примера я заюзал метод Записать(). Он выполняет передачу локального файла на FTP-сервер. Обрати внимание, вызов каждого метода я взял в блок «Попытка..исключение..КонецПопытки». Если ты знаком с понятием «Исключительные ситуации», то должен понять, для чего эта конструкция предназначена.
Другие полезные примеры
http://infostart.ru/public/20144 — ICQ-клиент, выполненный в виде внешней компоненты. Внутренности контрола состоят из C# кода и известной в .NET-кругах либы — IcqSharp 0.4.0.0. Хочешь чатиться в аське прямо из 1С? Тогда этот пример специально для тебя!
http://infostart.ru/public/14457 — смесь тети Аси и дяди Джаббера. Еще один внешний контрол и пример использования, при помощи которого ты сможешь закодить клиентские части для популярных протоколов передачи сообщений.
http://infostart.ru/public/20223 — здесь тусуется пример реализации «продвинутого» медиаплеера для платформы 1С:Предприятие 8.x. Умеет воспроизводить как видео, так и аудио-файлы.
http://infostart.ru/public/16332 — это не просто обработка, а настоящая кладезь примеров. Тут тебе и файловый менеджер, и FTP-клиент, и встроенный браузер, и диспетчер задач, и менеджер программ, и куча всякой полезной всячины. Заюзал такую обработку в 1С:Предприятии и забыл про многочисленные тулзы. Разве это не здорово?
Отправляем почту
FTP-клиент средствами 1С:Предприятие — это супер, но им одним сыт не будешь. Что ни говори, а обойтись без электронной почты крайне трудно. Что ж, если возможности юзать полноценный клиент у тебя нет, а из имеющего софта — лишь 1С:Предприятие, то считай, что тебе крупно повезло. Закодить на встроенном языке обработку для отправки/приема почты — проще пареной репы. Сейчас ты в этом убедишься (см. врезку «Почтовый клиент»).
Для отправки и приема почтовых сообщений в платформе 1С:Предприятие существует несколько готовых классов — ИнтернетПочтовоеСообщение, ИнтернетПочтовыйПрофиль, ИнтернетПочта. Первый — это, по сути, «обертка» электронного письма. В нем реализованы все необходимые поля для электронного письма: необходимость получения отчета о доставке, список получателей, прикрепленные файлы и т.д. От разработчиков (то есть, нас с тобой), требуется лишь правильно их заполнить. Именно это я описал в первой части кода — присвоил свойствам класса значения из полей ввода, расположенных на форме обработки.
Сформировав письмо, нам остается лишь прилепить на него почтовую марку и отправить по месту назначения. Для выполнения этого действия я использую второй класс — ИнтернетПочтовыйПрофиль. Если ты внимательно ознакомился со вторым листингом, то должен был уже догадаться, что этот класс — не что иное, как обертка для хранения настроек соединения с почтовыми серверами. В исходнике на врезке я привел вариант заполнения свойств для соединения с smtp-сервером своего почтового провайдера (через которого будет выполняться отправка).
Класс ИнтернетПочтовыйПрофиль лишь хранит настройки для подключения. Ничего отправлять/получать он не может. За саму передачу отвечает третий класс — «ИнтернетПочта». Во время инициализации ему необходимо передать экземпляр класса «ИнтернетПочтовыйПрофиль». После этого можно выполнять подключение и отправку. Тут тебе помогут методы «Подключиться» и «Послать». Кстати, не забывай заключать их в эксепшины, иначе замучаешься ловить вылеты.
Почтовый клиент
Письмецо = Новый ИнтернетПочтовоеСообщение; Письмецо.Тема = ЭлементыФормы.пвТемаПисьма.Значение; Письмецо.ИмяОтправителя = ЭлементыФормы.пвИмяОтправителя.Значение; Письмецо.Отправитель.Адрес = ЭлементыФормы.пвАдресОтправителя.Значение; Получатель = Письмецо.Получатели.Добавить(); Получатель.Адрес = ЭлементыФормы.пвАдресПолучателя.Значение; ТекстПисьма = Письмецо.Тексты.Добавить(); ТекстПисьма.ТипТекста = ТипТекстаПочтовогоСообщения.ПростойТекст; ТекстПисьма.Текст = пвТекстСообщения; Если (ЗначениеЗаполнено (ЭлементыФормы.пвАттач.Значение)) Тогда Письмецо.Вложения.Добавить( ЭлементыФормы.пвАттач.Значение); КонецЕсли; //Настраиваем параметры отправки ПрофайлНастроек = Новый ИнтернетПочтовыйПрофиль; ПрофайлНастроек.АдресСервераSMTP = ЭлементыФормы.пвПочтовыйСервер.Значение; ПрофайлНастроек.ПортSMTP = ЭлементыФормы.пвПортПочтовогоСервера.Значение; ПрофайлНастроек.АутентификацияSMTP = СпособSMTPАутентификации.ПоУмолчанию; ПрофайлНастроек.ПользовательSMTP = ЭлементыФормы.пвАдресОтправителя.Значение; Почтовик = Новый ИнтернетПочта; Попытка Почтовик.Подключиться(ПрофайлНастроек); Исключение Сообщить("Во время отправки возникла ошибка! Текст ошибка: " + ОписаниеОшибки(), СтатусСообщения.ОченьВажное); Возврат; КонецПопытки; //Пробуем отослать Попытка Почтовик.Послать(Письмецо); Сообщить("Ваше сообщение было успешно отправлено!", СтатусСообщения.ОченьВажное); Исключение Сообщить("Сообщение не было отправлено!" + ОписаниеОшибки(), СтатусСообщения.ОченьВажное); КонецПопытки; Почтовик.Отключиться();
Курим трубку, читаем новости
Я очень люблю читать RSS-ленты различных блоггеров. То и дело в них появляются интересные топики. Обычно для таких целей я юзаю Google Reader, но на старой работе приходилось пользоваться тулзой собственного изготовления. Ну а поскольку моя прошлая работа была связана с программированием под платформу 1С:Предприятие, то эту самую тулзу мне пришлось сваять на своем «рабочем» языке.
Сама RSS-лента — это XML-файл. Соответственно, работать с ним нужно, как с любой XML — парсить. В одном из номеров нашего журнала, я приводил пример RSS-граббера. Тогда мой пример был на Delphi. Для разбора XML я использовал COM-объект Microsoft.XMLHTTP. Ты не поверишь, но в 1С:Предприятии мы можем воспользоваться этим же объектом. Взгляни на врезку «RSS-агрегатор» и убедись сам.
RSS-агрегатор
НазваниеКанала = RSSЛента.selectSingleNode( "//channel/description").Text; Элементы = RSSЛента.selectNodes("//item"); Для сч = 0 по Элементы.length-1 Цикл СчитАтриб = Элементы.item(сч).childNodes; СтруктураАтрибутов = Новый Структура(); Для сч2 = 0 по СчитАтриб.length-1 цикл СтруктураАтрибутов.Вставить (СчитАтриб.item(сч2).nodeName, СчитАтриб.item(сч2).text); КонецЦикла; ЗаголовокНовости = "Заголовок: "; Если (СтруктураАтрибутов.Свойство("title")) Тогда ЗаголовокНовости = ЗаголовокНовости + СтруктураАтрибутов.title; КонецЕсли; ДатаПубликации = "Дата публикации: "; Если (СтруктураАтрибутов.Свойство("pubDate")) Тогда ДатаПубликации = ДатаПубликации + ДатаRFC822(СтруктураАтрибутов.pubDate); КонецЕсли; Линк = "Адрес публикации: "; Если (СтруктураАтрибутов.Свойство("link")) Тогда Линк = Линк + СтруктураАтрибутов.link; КонецЕсли; ТекстНовости = "Текст новости: "; Если (СтруктураАтрибутов.Свойство("description")) Тогда ТекстНовости = ТекстНовости + СтруктураАтрибутов.description; КонецЕсли; Сообщить("--------------------------"); Сообщить(ЗаголовокНовости); Сообщить(ДатаПубликации); Сообщить(Линк); Сообщить(ТекстНовости); Сообщить("--------------------------"); КонецЦикла;
Outro
При особом желании и настойчивости нужные тулзы реально закодить даже на таком, казалось бы, не предназначенном для подобных целей языке, как встроенный язык платформы 1С:Предприятие. Главное, не поленись потратить немного времени и попробуй подойти к решению проблемы творчески. Вполне возможно, что пришедшее на ум спонтанное решение будет намного лучше, чем то, которое прорабатывалось долгое время. Экспериментируй и все будет ОК!