Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #134, ФЕВРАЛЬ 2010 г.

Кодим на 1С: Предприятие по-хакерски

Игорь Антонов antonov.igor.khv@gmail.com, www.vr-online.ru


Платформа 1С:Предприятие сегодня установлена в каждой второй организации. Админы влюбились в эту систему за простоту администрирования и легкость развертывания. Программисты балдеют от возможности доработки/разработки конфигураций под конкретные нужды. Пользователи в восторге от продуманного и стандартизированного (среди продуктов 1С) интерфейса. А что представляет эта платформа для ][-совместимого чела?

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С:Предприятие языке! Ничто не помешает тебе заграбастать бэкап ценной базы данных и благополучно залить его на какой-нибудь сервак в инете.

С чего начинается кодинг под 1С

Встроенный язык 1С:Предприятия внешне очень сильно отличается от привычных нам С#, Python, Delphi и т. д. Главное отличие в том, что приходится использовать русский синтаксис. Проблема на первый взгляд не сильно большая, но по первости мозг рвет капитально. К счастью, это недоразумение победить возможно. Разработчики платформы 1С:Предприятие не зря получают свои деньги - они продумали все наперед и снабдили свое детище английским вариантом синтаксиса. Ты можешь юзать любой понравившийся вариант. Мне привычнее писать «по-русски», поэтому все листинги в статье будут приведены на великом и могучем. Если тебе по душе традиционный английский вариант — то милости прошу к встроенной документации. В ней описаны все функции/операторы: как в английской, так и в русской версиях.

Основы синтаксиса

Если мне не изменяет память, в нашем журнале еще ни разу не рассматривали кодинг под 1С:Предприятие, поэтому перед тем, как перейти к рассмотрению вопросов разработки реальных приложений, нужно обязательно познакомиться с базовым синтаксисом.

Регистр

Встроенный язык в 1С:Предприятие не чувствителен к регистру. Ты можешь писать название операторов/переменных прописными или строчными буквами - все будет работать одинаково хорошо.

Переменные

Как и во многих языках программирования, переменные ты можешь объявлять по ходу пьесы. Никаких областей типа дельфийского var нет (если не считать ключевого слова «Перем» для объявления глобальных переменных). С типами переменных ситуация аналогичная. Указывать для переменной конкретный тип в момент ее определения не требуется. Он выбирается на основе содержимого переменной. Пример:

СтроковаяПеременная = «Hello, world!»; //Это строковая переменная
ЧисловаяПеременная = 0; //А вот это числовая переменная
Массив = Новый Массив(); //Ну а это массив

Процедуры, функции

В 1С:Предприятии принято делить весь код на процедуры и функции. Определяются они стандартным образом:

//Процедура без параметров
Процедура ПримерПроцедуры()
КонецПроцедуры

//Процедура с параметрами
Процедура ПримерПроцедуры(Параметр1, Параметр2)
КонецПроцедуры

//Пример функции
Функция ПолучитьДиректорию(Параметр1, Параметр2)
Возврат Параметр1 + Параметр2;
КонецФункции

Циклы

Во встроенном языке реализовано несколько видов циклов. По синтаксису они не особо отличаются от оформления аналогичных циклов в других языках программирования. Взгляни на примеры:

//Цикл «Пока». Аналогичен циклу 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-клиент. Да не просто написать, а закодить на языке, совершенно не предназначенном для этой цели.

Итак, запускай 1С:Предприятие в режиме «Конфигуратор» и создавай новую обработку. Я не буду тебе расписывать, как работать с самой IDE, так как это выходит за рамки статьи. Всю необходимую инфу ты сможешь посмотреть в хелпе. Лучше сразу к коду.

В 1С:Предприятии для работы с протоколом FTP есть встроенный и полностью готовый к работе класс: FTPСоединение. Класс достаточно хорош и в нем реализованы все необходимые свойства и методы. Тут тебе и поддержка работы через PROXY-сервер, и закачка/передача файлов и т. д.

Не буду ходить вокруг да около, а сразу перейду к рассмотрению рабочего примера. Вот код, отвечающий за соединение и отправку произвольного файла:

FTP-клиент средствами 1С:Предприятия

ИмяПользователя = "Логин”;
Пароль = "";
Сервер = "Имя сервера”;
КаталогДляЗаписи = "папка для записи”;

Попытка
FTPСоединение = Новый FTPСоединение(Сервер,
, ИмяПользователя, Пароль);
FTPСоединение.УстановитьТекущийКаталог(
КаталогДляЗаписи);
Исключение
Сообщить("При попытки соединения с FTP
| сервером возникла ошибка!",
СтатусСообщения.Важное);

Сообщить(ОписаниеОшибки());
Возврат;
КонецПопытки;

Попытка
FTPСоединение.Записать(
ЭлементыФормы.пвПутьКФайлу.Значение,
ЭлементыФормы.ПолеВвода1.Значение);
Исключение
Сообщить("Во время передачи файла возникла ошибка!",
СтатусСообщения.Важное);
Сообщить(ОписаниеОшибки());
КонецПопытки;

Установка соединения по FTP начинается с инициализации класса «FTPСоединение». В качестве параметров конструктору необходимо передать следующие параметры:

  • Сервер — адрес FTP-сервера (обязательный)
  • Порт — номер порта FTP-сервера (необязательный)
  • ИмяПользователя — пользователь на FTP-сервере
  • Пароль
  • Прокси — объект, содержащий настройки PROXY-сервера (необязательный)
  • ПассивноеСоединение — Тип соединения (необязательный)

Если инициализация пройдет успешно, то FTP-соединение будет установлено. Ну а после его установки ты можешь воспользоваться одним из методов класса. Например, в своем примере я вызвал УстановитьТекущийКаталог().

Для демонстрации работоспособности примера я заюзал метод Записать(). Он выполняет передачу локального файла на FTP-сервер. Обрати внимание, вызов каждого метода я взял в блок «Попытка..исключение..КонецПопытки». Если ты знаком с таким понятием как «Исключительные ситуации», то должен понять, для чего эта конструкция предназначена.

Отправляем почту

FTP-клиент средствами 1С:Предприятие – это супер, но им одним сыт не будешь. Что не говори, а обойтись без электронной почты крайне трудно. Что ж, если возможности юзать полноценный клиент у тебя нет, а из имеющего софта — лишь 1С:Предприятие, то считай, что тебе крупно повезло. Закодить на встроенном языке обработку для отправки/приема почты – проще пареной репы. Сейчас ты в этом убедишься (см. врезку «Почтовый клиент»).

Почтовый клиент

Письмецо = Новый ИнтернетПочтовоеСообщение;
Письмецо.Тема =
ЭлементыФормы.пвТемаПисьма.Значение;
Письмецо.ИмяОтправителя =
ЭлементыФормы.пвИмяОтправителя.Значение;
Письмецо.Отправитель.Адрес =
ЭлементыФормы.пвАдресОтправителя.Значение;

Получатель = Письмецо.Получатели.Добавить();
Получатель.Адрес =
ЭлементыФормы.пвАдресПолучателя.Значение;

ТекстПисьма = Письмецо.Тексты.Добавить();
ТекстПисьма.ТипТекста =
ТипТекстаПочтовогоСообщения.ПростойТекст;
ТекстПисьма.Текст = пвТекстСообщения;

Если (ЗначениеЗаполнено
(ЭлементыФормы.пвАттач.Значение)) Тогда
Письмецо.Вложения.Добавить(
ЭлементыФормы.пвАттач.Значение);
КонецЕсли;

//Настраиваем параметры отправки
ПрофайлНастроек =
Новый ИнтернетПочтовыйПрофиль;
ПрофайлНастроек.АдресСервераSMTP =
ЭлементыФормы.пвПочтовыйСервер.Значение;
ПрофайлНастроек.ПортSMTP =
ЭлементыФормы.пвПортПочтовогоСервера.Значение;
ПрофайлНастроек.АутентификацияSMTP=
СпособSMTPАутентификации.ПоУмолчанию;
ПрофайлНастроек.ПользовательSMTP =
ЭлементыФормы.пвАдресОтправителя.Значение;

Почтовик = Новый ИнтернетПочта;

Попытка
Почтовик.Подключиться(ПрофайлНастроек);
Исключение
Сообщить("Во время отправки возникла ошибка!
Текст ошибка: "
+ ОписаниеОшибки(), СтатусСообщения.ОченьВажное);
Возврат;
КонецПопытки;

//Пробуем отослать
Попытка
Почтовик.Послать(Письмецо);
Сообщить("Ваше сообщение было успешно отправлено!",
СтатусСообщения.ОченьВажное);
Исключение
Сообщить("Сообщение не было отправлено!" +
ОписаниеОшибки(),
СтатусСообщения.ОченьВажное);
КонецПопытки;

Почтовик.Отключиться();

Для отправки и приема почтовых сообщений в платформе 1С:Предприятие существует несколько готовых классов – ИнтернетПочтовоеСообщение, ИнтернетПочтовыйПрофиль, ИнтернетПочта. Первый – это, по сути, «обертка» электронного письма. В нем реализованы все необходимые поля для электронного письма: необходимость получения отчета о доставке, список получателей, прикрепленные файлы и т.д. От разработчиков (то есть, нас с тобой), требуется лишь правильно их заполнить. Именно это я описал в первой части кода – присвоил свойствам класса значения из полей ввода, расположенных на форме обработки.

Сформировав письмо, нам остается лишь прилепить на него почтовую марку и отправить по месту назначения. Для выполнения этого действия я использую второй класс – ИнтернетПочтовыйПрофиль. Если ты внимательно ознакомился со вторым листингом, то должен был уже догадаться, что этот класс – не что иное, как обертка для хранения настроек соединения с почтовыми серверами. В исходнике на врезке я привел вариант заполнения свойств для соединения с 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С:Предприятие. Главное, не поленись, потратить немного времени и попробуй подойти к решению проблемы творчески. Вполне возможно, что пришедшее на ум спонтанное решение будет намного лучше, чем то, которое прорабатывалось долгое время. Пробуй, экспериментируй и все будет ОК!

Другие полезные примеры

  • 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С:Предприятии и забыл про многочисленные тулзы. Разве это не здорово?
Содержание