Написание внешних компонент для 1С (Delphi)В статье описана разработка внешних компонент для 1С:Предприятие в среде программирования Delphi.
Я постарался создать удобный для понимания и функциональный шаблон внешней компоненты, который можно было бы использовать без предварительной подготовки, зная, в общих чертах, программирование в Delphi. Пример внешней компоненты для скачивания приведен в конце статьи. | | Автор статьи: romix | Редакторы: pectopatop, Последняя редакция №4 от 06.08.06 | История URL: http://kb.mista.ru/article.php?id=319 | |
Ключевые слова: Внешняя компонента, DLL, 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);
Этот вызов покажет стандартное окно предупреждения с кнопкой ОК.
Получение параметров функции
В своей функции я завел две переменные для хранения параметров:
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);
А числовые значения я отображаю примерно так:
MessageBox(0, pchar(IntToStr(ms)), 'Отладка - ms', 0);
Функциональность методов
Получив все значения из 1С, можно приступать к собственно написанию полезного кода.
Функция sleep_icon(s, ms); определена в коде примера, и показывает сообщение, используя функции Windows API (Application Programming Interface).
Узнавать, как работают те или иные функции API, можно в поисковых машинах или в сборниках Delphi FAQ, которые в изобилии выложены в сети Интернет.
Хороший сборник рецептов и примеров – диск MSDN от Microsoft.
Пример для скачивания
http://x-romix.narod.ru/TestVK.rar
(Скачивать левой кнопкой мыши, 80 килобайт).
|