Программирование arrow Delphi arrow Написание внешних компонент для 1С на Delphi

Написание внешних компонент для 1С на Delphi

Насколько мне известно, многие 1С-ники хотели бы изучить написание внешних компонент, чтобы поднять свое магическое искусство 1С на качественно иную ступень. Что этому может помешать? Во-первых, известный синдром компонентофобии (который исторически берет свое начало от криво написанных внешних компонент). Во-вторых –синдром  клинически запутанного кода. OLE-программирование – это не самая простая штука, и, как говорится, «не всякая птица долетит до середины Днепра» (особенно, если эта «птица» – программист 1С). Я предлагаю вашему вниманию шаблон внешней компоненты, который, как я надеюсь, достаточно прост для понимания (я постарался его значительно упростить по сравнению с типовым примером из «Технологии создания внешних компонент») и стабилен (везде, где это возможно, я использую обработку исключительных ситуаций).

Сборка проекта

Для компиляции примера потребуется среда разработки Delphi 6 или 7.

Файл проекта - TestVK.dpr.

Откройте этот файл (например, двойным щелчком мыши из Проводника). Нажмите сочетание клавиш Ctrl-F9 (или пункт меню Project-Compile). Если все прошло нормально, в этой же папке образуется готовая внешняя компонента  TestVK.dll (для проверки, а все ли хорошо, ее можно удалить, и получить готовую TestVK.dll еще раз).

При компиляции должна быть закрыта программа 1С в режиме Предприятие – иначе файл DLL будет заблокирован системой, и Delphi напишут пугающее сообщение: [Fatal Error] Could not create output file 'TestVK.dll'

Проверка работоспособности DLL

В комплект примера входит тестовая конфигурация 1С:Предприятие 7.7. Если компонента зарегистрировалась нормально (возможно, потребуется вход в Windows и первый запуск под правами администратора), то откроется отчет, в котором доступны кнопки "Сообщение", "Предупреждение" и "Сигнал" (я реализовал три метода для вывода информации из внешней компоненты - знать, как работают подобные вещи, часто бывает полезно для отладки).

Переименование DLL

Первое, что я делаю при создании новой внешней компоненты – переименовываю уже существующий образец. Переименуйте TestVK.dpr так, как вы хотите (например, MyVK.dpr). Произведите замену всех вхождений подстроки TestVK в файлах проекта на нужное вам имя внешней компоненты.

Подсказка: чтобы открыть другие модули проекта, используйте пункт меню View-Units…

Программный код 1С, разумеется, также нужно не забыть изменить так, чтобы заменить все подстроки «TestVK».

Важно: замените значение CLSID внешней компоненты, чтобы новая DLL, с точки зрения Windows, стала действительно новой.
     CLSID_AddInObject : TGUID = '{CE4FB6DB-636C-4824-86C4-DCE02135FE5A}';
Чтобы сгенерировать новый CLSID, нажмите сочетание клавиш Ctrl-Shift-G. Попробуйте скомпилировать новый проект – 1С должна «увидеть» вашу новую внешнюю компоненту, которая создана на основе другой ВК, но содержит полный набор ее свойств и методов.

Что такое свойства и методы?

Новички могут задаться вопросом, а что такое свойства и что такое методы? В коде 1С свойства выглядят как, своего рода, «переменные», объекта, доступные через точку, например
    vk.Заголовок="Внешняя компоннета";
Здесь объект – имеет имя vk (посмотрите, как он объявляется и инициализируется в глобальном модуле 1С). Этот объект поддерживает свойства и методы.

В этом коде я установил свойству "Заголовок" текстовое значение (посмотрите, как будет работать пример, если установить этому свойству другое значение заголовка, например, «Здесь был romix», или не устанавливать его вовсе).

Метод объекта – это, своего рода, «функция» объекта, доступная «через точку».
    vk.ВсплывающаяПодсказка("Проверка всплываюшего сообщения", 3000);
Метод может иметь параметры. В данном примере, параметры – это «Проверка всплывающего сообщения» и 3000 – попробуйте установить в коде 1С что-нибудь другое и нажать кнопку «Сообщение» в тестовом отчете.

Изменение списка свойств и методов ВК

В модуле AddinObj.pas за количество свойств отвечают участки кода, которые я пометил (*2*), (*5*), (*6*), (*8*), (*11*) а за количество методов - (*3*), (*7*), (*9*), (*10*), (*12*). Я завел в шаблон по 5 свойств и методов, но что нужно сделать, чтобы их стало 6, например, в приведенном ниже фрагменте кода, - я надеюсь, понятно без объяснений.
            prop1: vk_object.prop1(m_get_value);
            prop2: vk_object.prop2(m_get_value);
            prop3: vk_object.prop3(m_get_value);
            prop4: vk_object.prop4(m_get_value);
            prop5: vk_object.prop5(m_get_value);
Вы можете завести свойства и методы «с запасом» - лишние заготовки не повредят (их можно будет оставить пустыми).

Программирование функциональности свойств

Откройте (через меню View – Units…) модуль vk_object.pas

Для свойств вы увидите примерно такой код, продублированный, с небольшими отличиями, несколько раз: Это самая важная часть наших действий, которую важно постараться понять.
  /////////////////////////////////////////////////////////////////////
  function T_vk_object.prop1(mode: TMode): String;
  begin
    case mode of
      m_rus_name: Result:='Пиктограмма';
      m_eng_name: Result:='IconType';
      m_get_value: g_Value:=g_IconType;
      m_set_value: g_IconType:=g_Value;
    end;//case
  end;
Что я здесь делаю?

# m_rus_name – устанавливаю русское имя свойства (в данном случае, свойство называется Пиктограмма). В коде 1С я пишу что-то вроде
vk.Пиктограмма=32;

Вот здесь 1С и узнает, что свойство называется именно Пиктограмма (а не как-то иначе). Попробуйте переименовать свойство (например, в Псиграмма), и посмотрите, что получится.

# m_eng_name - англоязычный синоним - 'IconType' – я устанавливаю строкой ниже.

# m_get_value –1С получает значение переменной, в данном случае, g_IconType.

Что это за переменная? А это та переменная (точнее, свойство класса), где я решил запоминать идентификатор своей пиктограммы.

# m_set_value – 1С устанавливает значение свойства. Наличие этой строки позволяет изменять числовое значение моей пиктограммы из кода 1С. Попробуйте выставлять из кода 1С различные значения пиктограммы (в комментариях примера я описал, какие значения возможны), и смотреть, что получится.

Программирование функциональности методов

Для методов код похожий:

  /////////////////////////////////////////////////////////////////////
  function T_vk_object.meth1(mode: TMode): String;
  var s: String;
  var ms: Integer;
  begin
    case mode of
      m_rus_name: Result:='ВсплывающаяПодсказка';
      m_eng_name: Result:='BalloonTooltip';
      m_n_params: g_NParams:=2; //Количество параметров функции
      m_execute: begin
        //Извлекаем параметры функции, переданные из 1С
        s:=GetParamAsString(0);//сообщение
        ms:=GetParamAsInteger(1);//задержка в мс
        //Показываем сообщение в трее
        sleep_icon(s, ms);
      end;
    end;//case
  end;

Этот абзац можно воспроизвести несколько раз (что и сделано в примере), заменив meth1 на meth2, meth3 и т.д. Приведенные ниже строчки устанавливают русское и английское имя метода.

      m_rus_name: Result:='ВсплывающаяПодсказка';
      m_eng_name: Result:='BalloonTooltip';

Попробуйте изменить то или другое, перекомпилировать проект и посмотреть, что получится. В строчке

    m_n_params: g_NParams:=2; //Количество параметров функции

я устанавливаю количество параметров метода. Попробуйте изменять это количество (например, установить значение 3) и посмотреть, что получится. Блок

      m_execute: begin
//…
      end;

реализует собственно функциональность метода (показывает всплывающее сообщение в трее). Подробнее код я опишу ниже – но сначала полезно потренироваться со вставкой в него отладочной печати (именно так я исследую код).

Отладочная печать

Вы можете в качестве теста вписать в функциональность метода что-то свое, например,

MessageBox(0, 'Превед', 'Медвед', 0);

Этот вызов покажет стандартное окно предупреждения с кнопкой ОК. Или вот так:

ShowMessage('Просто текст');

Во втором случае, если Delphi будет ругаться при компиляции, добавьте Dialogs в раздел uses модуля.

Получение параметров функции

В своей функции я завел две переменные для хранения параметров:

  var s: String;
  var ms: Integer;

Они должны хранить, соответственно, текст сообщения (то, что я передаю из 1С) и значение паузы в миллисекундах, в течение которой будет высвечиваться сообщение в трее. Сейчас мы их заполним значениями, полученными из 1С.

        s:=GetParamAsString(0);//сообщение
        ms:=GetParamAsInteger(1);//задержка в мс

Параметры нумеруются, начиная с 0 (давняя традиция программистов на языке С). Чем отличаются AsString и AsInteger, надеюсь, понятно. Этот код можно было бы написать и так:

        s:= GetNParam(0);//сообщение
        ms:= GetNParam(1);//задержка в мс

Но в случае передачи значений неправильного типа (попытайтесь передавать вместо правильных значений различную "чепуху") сообщения об ошибке будут менее информативными.

Отладочная печать параметров

При отладке полученные из 1С значения полезно выводить на экран. Но как это сделать? Я обычно использую следующий прием. Чтобы показать строковые переменные, я пишу так:

MessageBox(0, pchar(s), 'Отладка - s', 0);

А числовые значения и значение типа "дата-время" я отображаю примерно так:

ShowMessage('Отладка - ms'+#13+IntToStr(ms));
ShowMessage('Время = <'+TimeToStr(Now())+'>; Температура = <'+FloatToStr(RoundTo(t,-2))+'>');

Функциональность методов

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

Функция sleep_icon(s, ms); определена в коде примера, и показывает сообщение, используя функции Windows API (Application Programming Interface).

Скачать пример

 
Следующая статья »


  • Delphi, Вывод графиков функций в Delphi
    Изучая доступную литературу по программированию, которую я нашел в Интернете, а также некоторые программы, я пришел к выводу, что программисты то ли не осознают, то ли не хотят напрягаться на эту тему, и всё делают, как в школе учили. Строят графики, как на бумаге. Тем самым умаляя возможности компьютера. Оставляя те же недостатки метода построения, и даже усугубляя их....
  • Delphi, Приемы работы с базами данных в Delphi
    Данная статья предназначена в основном для тех, кто начинает работать с базами данных. Здесь собраны приемы, направленные на оптимизацию и ускорение работы с базами данных. Описанные примеры являются результатом многолетней работы автора с СУБД MS SQL Server, Oracle и Access. Примеры описываются в общем виде, без привязки к какой-либо конкретной СУБД....
  • Delphi, Работа с потоками в Delphi
    Данная статья предназначена для начинающих программистов, которые никогда не работали с потоками, и хотели бы узнать основы работы с ними. Желательно, чтоб читатель знал основы ООП и имел какой-нибудь опыт работы в Delphi. Для начала давайте определимся, что под словом "поток" я подразумеваю именно Thread, который еще имеет название "нить"....
  • Delphi, Message методы, или обработка сообщений классами в Delphi
    Данная статья предназначения для более глубокого понимания того, как реализована обработка сообщений Windows в VCL и как это можно и нужно использовать в своих целях и использовать правильно....
  • Delphi, Запись CD-DVD дисков в Delphi
    Доброго времени суток уважаемые любители Delphi. В этой статье я расскажу про запись CD\DVD дисков в среде Delphi. Общие принципы, изложенные в этой статье подойдут не только для языка Delphi, но и для языка С++. Для прочтения этой статьи с максимальной пользой, читателю рекомендуется получить базовые понятия об OLE\COM, впрочем даже незнание этих понятий вряд ли помешает понимаю этой статьи, так как классы и компоненты Delphi (так же как и классы С++), которые мы будет использовать полностью ск...
  • Delphi, Хуки в Windows на Delphi
    Тема про хуки является популярной на многих форумах программистов. Материал этих статей рассчитан на начинающего пользователя, примеры будут на Delphi. В этой статье будут изложены основные принципы механизма хуков, и будет написан пример клавиатурного шпиона....
  • Delphi, Перехват API функций в Delphi с помощью сплайсинга
    Сегодня я расскажу довольно таки эффективную методику перехвата API функций. Не следует думать, что если мы хотим перехватить API функции, то мы пишем либо троян, вирус и ещё какую-нибудь заразу, с помощью перехвата API функций осуществляются многие защитные механизмы, перехват API функций это довольно-таки нужная и полезная вещь. Для прочтения данной статьи с максимальной пользой обязательны, нужны, как минимум, начальные знания низкоуровневого программирования и хотя бы какие-нибудь знания арх...
  • Delphi, Delphi: Работа с устройствами в Windows
    Функции, которые осуществляют работу с устройствами, находятся в системных библиотеках cfgmgr32.dll и setupapi.dll. К сожалению, в стандартных заголовочных файлах Delphi нет объявлений функций, констант и структур которые используются этими библиотеками. Эти заголовочные файлы можно скачать с сайта проекта Delphi-JEDI. Те, кому не нравятся модули от проекта Delphi-JEDI могут воспользоваться моим модулем setupapi.pas, но в нём далеко не полный список функции и структур....