Переключение на Главную Страницу Страницы: 1 ОтправитьПечать
Обычная тема Новый старый "движок" для простого написания сложных компонент 1С (число прочтений - 3700 )
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Новый старый "движок" для простого написания сложных компонент 1С
27. Марта 2013 :: 21:52
Печать  
Прямого отношения к 1С++ вопрос, правда, не имеет, но выложить пока не знаю куда, а мысли излить хочется. Поэтому, простите, ворвусь пока к Вам. Может кому даже пригодится.

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

За основу был взят "движок", изначально писанный Александром Орефковвым, и лежавший в инете вместе с исходниками компоненты VKLoader. Понравился он за некоторые оригинальные приёмы в нём использованные. Однако от первоначально кода практически ничего не осталось. Хотя новый написан, так сказать, "по образу и подобию". Осталась только большая часть самого VKLoader'а, который, однако, тоже пришлось немного подкорректировать из-за некоторых обнаруженных неисправностей и в нём самом, и в том самом "движке", на котором он был написан. О некоторых из них уже писал я здесь: http://www.1cpp.ru/forum/YaBB.pl?num=1363585909

Основные (хотя и не все) исправления "движка":
  • Исправлена генерация runtime информации о классе (GetRuntimeClass). Теперь она генерируется правильно (и также полностью автоматически, как и раньше). Раньше не работало создание объектов после загрузки 1С++ (см. указанную выше тему).
  • Улучшено получение свойств и методов по индексу (в изначальной версии это разворачивалось из шаблона в код вида if (Index==0) ... else if (Index==1) ... else if (Index==2) ... (тем более обидно долго парится с хэшами для имен, если потом, имея индекс, генерим такой некрасивый код). Теперь берётся из массива типа Items[Index].
  • Полностью переработаны все структуры данных, в том числе хэш-таблицы для получения членов класса по именам. Код стал гораздо аккуратнее и даже чуточку быстрее.

Самые важные новые возможности:
  • Возможность наследования созданных объектов друг от друга. При этом хэш-таблицы для наследованных объектов строятся свои, что повышает эффективность обращения к их свойствам без необходимости искать не перекрытые свойства в базовом классе. GetRuntimeClass в этом случае также выдает правильную runtime информации о наследованном классе.
  • Возможность дополнения статического набора свойств и методов динамическими (которые меняются в процессе выполнения программы), что незаменимо при реализации таких объектов как Структура или ВыполняемыйМодуль. Все преобразования индексов свойств происходят автоматически, причем не в ущерб эффективности для тех объектов, в которых динамических свойств нет.

Грузятся компоненты сами на любом компе без админских прав (что и понятно при использовании родных механизмов 1С, а не ОЛЕ). Нужно только не забывать в ресурсах:
Код
Выбрать все
STRINGTABLE DISCARDABLE
BEGIN
    100			   "\0hello, world!"
END 


Компилировать DEBUG версию нужно с дефайном __DEBUG вместо _DEBUG и без отладочных библиотек. Иначе AfxGetApp возвращает NULL вместо 1Совского CApp7. Папка 1cheaders должна лежать на одном уровне с папками проектов, а папка Libs внутри нее. 1cheaders взята из последних исходников 1С++, но с парой маленьких изменений, поэтому если кому понадобится: http://yadi.sk/d/CRHR8rd33akKi

Новый "движок", как и подправленная версия VKLoader'а, уже предварительно протестированы на практике в реально работающей фирме с несколькими серверами (на каждом работает по несколько копий 1С) и несколькими десятками клиентских машин с пользовательскими правами.
« Последняя редакция: 25. Апреля 2013 :: 05:51 - dfuy »  

mycontimpl.7z ( 49 KB | Загрузки )
Наверх
 
IP записан
 
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Re: Новый старый "движок" для простого написания сложных компонент к
Ответ #1 - 27. Марта 2013 :: 21:54
Печать  
Переделанный VKLoader
  

vkloader_001.7z ( 12 KB | Загрузки )
Наверх
 
IP записан
 
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Re: Новый старый "движок" для простого написания сложных компонент к
Ответ #2 - 27. Марта 2013 :: 21:56
Печать  
Использовать новый "движок" крайне просто:
Код
Выбрать все
#include "stdafx.h"
#include "../_mycommon/mycontimpl.hpp"

class CTest: public CContextImpl<CTest>
{
public:
BL_BEGIN_CONTEXT("Test", "Тест")
	BL_PROP_RO (Test, "Тест") {Value="<prop>";}
	BL_FUNC (Func, "Функ", 0) {Value="<func>";}
BL_END_CONTEXT()
};
BL_INIT_CONTEXT(CTest);

class CTest2: public CContextImpl<CTest2, CCreateObject<CTest2>, CTest>
{
public:
BL_BEGIN_CONTEXT("Test2", "Тест2");
	BL_PROP_RO (Test, "Тест")
		{Base::getTest(Value);
		Value=Value.GetString()+".<prop2>";}
BL_END_CONTEXT()
};
BL_INIT_CONTEXT(CTest2);

extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
	if (dwReason==DLL_PROCESS_ATTACH) {
		DisableThreadLibraryCalls(hInstance);
		if (!Init1CGlobal()) return 0;
		CContextBase::InitAllContextClasses();
	} else if (dwReason==DLL_PROCESS_DETACH) {
		CContextBase::DoneAllContextClasses();
		Done1CGlobal();
	}
	return 1;
} 



Результат работы будет примерно такой:
Код
Выбрать все
ЗагрузитьВнешнююКомпоненту(КаталогИБ()+"test.dll");

Тест=СоздатьОбъект("Тест");
Сообщить(Тест.Тест); // <prop>
Сообщить(Тест.Функ()); // <func>
Тест=СоздатьОбъект("Тест2");
Сообщить(Тест.Тест); // <prop>.<prop2>
Сообщить(Тест.Функ()); // <func> 



Для иллюстрации элементарных возможностей смотрите в архиве проект "testdll". Скомпилированную DLLку тоже прилагаю.
  

testdll.7z ( 10 KB | Загрузки )
Наверх
 
IP записан
 
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Re: Новый старый "движок" для простого написания сложных компонент к
Ответ #3 - 27. Марта 2013 :: 21:59
Печать  
Для иллюстрации возможностей "движка" также приложил реальную компоненту, реализующую несколько нетривиальных объектов, таких как РасшСтруктура, РасшСписокЗначений, ОбъектныйМодуль.

РасшСтруктура и РасшСписокЗначений в целом повторяют функциональность объектов Структура из 1С++ и СписокЗначений из самой 1С (не все методы реализованы, только основные). Отличие в том, что в них добавлены новые методы для вставки "ссылок без блокировки", позволяющие организовывать циклические ссылки (которые, как известно, нельзя делать с обычными объектами, потому что память из под таких объектов не будет освобождена). Не буду объяснять, для чего это было необходимо на практике – это отдельная тема, на которой можно развести большой срач обширную дискуссию и долго спорить о стилях программирования (чего делать совершенно не хочется).
Использовать можно так:
Код
Выбрать все
Родитель=СоздатьОбъект("РасшСтруктура");
Родитель.Вставить("Объекты", СоздатьОбъект("СписокЗначений"));
Объект=СоздатьОбъект("РасшСтруктура");
Объект.ВставитьБезБлокировки("Родитель", Родитель);
Родитель.Объекты.ДобавитьЗначение(Объект); 


Или в любых подобных и более сложных комбинациях. В метод ВставитьБезБлокировки() можно передавать и ссылки на обычные объекты 1С типа СписокЗначений или ТаблицаЗначений. При этом корректно будет работать и "неправильное" использование "ссылок без блокировки" типа такого:
Код
Выбрать все
Объект.ВставитьБезБлокировки("Ссылка", СоздатьОбъект("СписокЗначений")); 


Созданный список значений должен будет тут же уничтожиться, поскольку Объект ссылается на него без блокировки, а больше на него не ссылается никто. Так и произойдет и свойство Ссылка просто примет значение типа ПустоеЗначение. Также корректно отработает такой код:
Код
Выбрать все
Родитель=СоздатьОбъект("РасшСтруктура");
Объект.ВставитьБезБлокировки("Родитель", Родитель);
Родитель=0; 


После Родитель=0 свойство Объект.Родитель также примет ПустоеЗначение. Если же передать в методы ...БезБлокировки() не объект, а обычное значение (число, строку и т.д.), они просто сработают как обычные.

РасшСписокЗначений также крайне выгодно отличается от своего собрата в 1С тем, что все методы, работающие с ключами (Установить, Получить, ДобавитьЗначение со вторым параметром), реализованы, как и РасшСтруктура, с использованием хэширования. Знающие люди поймут разницу между O(n2) при бездумном использовании этих методов в объекте СписокЗначений и O(n) в РасшСписокЗначений (при ограниченном количестве коллизий). Кстати, функция для расчета хэша строк безбожно тестировалась и подгонялась для достижения наибольшей равномерности и показывает довольно сносные результаты. Хотя, наверняка, можно придумать и получше.
Также РасшСписокЗначений содержит настройку ЧувствительностьКРегистру, которая соответствующим образом влияет на работу методов с ключами (по умолчанию чувствителен к регистру). Список.ЧувствительностьКРегистру(0) делает его к регистру не чувствительным (как Структура).

Кстати, из-за применения нового движка, а также свежесамописанных упрощенных хэш-таблиц и коллекций эти объекты работают даже немного быстрее, чем в 1С++. И это еще компилиные УЖАСНЫМ компилятором VS6. Как он меня достал! Щас вот закончу пока с написанием компонент и пойду снесу его на#@$. Буду пробовать ставить что-нибудь посвежее из VS и прикручивать к ней Intel Compiler. Даже самый банальный оптимизатор способен сгенерировать код, работающий раза в 3 быстрее, чем после VS6. Я уж не говорю про постоянные Inetrnal Compiler Error, или тупо "Свойство такое-то в таком-то классе не обнаружено", хотя оно там заведомо есть, или вообще забавную компиляцию, когда, например, вместо функции из некоего базового класса функция вызывает саму себя со всеми вытекающими из этого прелестями.

Ладно, ближе к делу. ОбъектныйМодуль – примитивная замена объектно-ориентированному программированию, которое из 1С++ я так и не решился использовать (слишком уж экстремальным для меня все еще выглядит такое решение), но без которого уже давно вешаюсь и убиваюсь головой об стену. Для самых банальных случаев подойдет ОбъектныйМодуль. Он просто грузит код из файла .ERT и все переменные и процедуры с функциями (точнее только экспортированные, но это настраивается) становятся доступными как свойства и методы объекта. Код компилируется и исполняется с корректной выдачей ошибок точно как в обычных модулях 1С и с переходом по клику в конфигуратор. Правда не проверял как работает отладка, да и вообще еще особо его не тестировал. Может кому пригодится пока хотя бы как пример реализации динамических методов и свойств в описываемом "движке".

Исходники в первом файле, DLL тут:
« Последняя редакция: 27. Марта 2013 :: 23:53 - dfuy »  

mltrade2.7z ( 17 KB | Загрузки )
Наверх
 
IP записан
 
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Re: Новый старый "движок" для простого написания сложных компонент к
Ответ #4 - 27. Марта 2013 :: 22:25
Печать  
Вот пока и всё, что хотел сказать. Остальным мануалом да будет исходный код (там даже комментарии кое-где есть Улыбка ). Хотя на вопросы и предложения ответить готов.
  
Наверх
 
IP записан
 
Переключение на Главную Страницу Страницы: 1
ОтправитьПечать