Проект внешней компоненты для 1С:8 (сделай сам)

Публикация № 484743

Разработка - Разработка внешних компонент

Проект внешней компоненты

Как их делают? Как регистрируют? С чего начать? Где взять стартовый проект? Вопросов вообще много можно задать, но лучше один раз увидеть!

Запускаем vs2013 (у меня community).

 

Обычно после этого нужно создавать проект или открывать существующий. Т.к. мы начинаем с нуля, то будем создавать (Файл\Создать\Проект).

В открывшееся окно обычно не вызывает застревания, но мы проговорим и это. Выбираем в дереве "Visual C++", а в списке "Консольное приложение Win32". Теперь трудный момент - нужно придумать название или имя. Проблема обычно в том, что мы не знаем, чего хотим.

Давайте назовем проект SuperI. Нажимаем "Ок" и открывается мастер. К счастью, на первой закладке ничего не нужно вводить и отмечать. Жмем "Далее".

Со второй закладкой все совсем иначе (уже что-то заполнено, а мы еще мало что понимаем). Переставляем отметку с "Консольное приложение" на "Библиотека DLL". Не спешите нажимать "Готово", мы ведь хотим совсем с нуля, правда? Надо отметить пустой проект, а уже потом нажимать "Готово".

Ну вот, это оно - наш пустой проект. В этом месте обычно вспоминают о дисках ИТС и прочем. Нам понадобится кое-что добавить. Прикрепил это к публикации. Лучше сложить файлы в каталог <путь до>\Documents\Visual Studio 2013\ProjectsCPP\SuperI\SuperI, а потом добавить их в проект.

Добавить нужно ряд заголовочных файлов (Проект\Добавить существующий элемент):

1. adapter.h - Базовый интерфейс объекта платформы (для взаимодействия с платформой 1С)

2. memory_adapter.h - Предопределенный класс, для выделения и освобождения памяти в платформе

3. base.h - интерфейс для инициализации компоненты, предопределенный интерфейс описания методов предназначенный для использования платформой 1С,  интерфейс для изменения локализации в компоненте

4. com.h

5. types.h

Добавим еще и файл исходного кода (Проект\Добавить существующий элемент):

1. dllmain.cpp - стандартная точка входа в библиотеку

Увы и ах, но это еще не конец. Нам нужен манифест. Делаем файл с именем MANIFEST.XML в папке с проектом <путь до>\Documents\Visual Studio 2013\ProjectsCPP\SuperI (в этом каталоге лежит папка SuperI с нашим исходным кодом).

А вот и содержание этого файла:

<?xml version="1.0" encoding="UTF-8"?>
<bundle xmlns="http://v8.1c.ru/8.2/addin/bundle">
  <component os="Windows" path="SuperI.dll"     type="native" arch="i386"  />
  <component os="Windows" path="SuperI64.dll"   type="native" arch="x86_64"/>
  <component os="Linux"   path="SuperI.so"      type="native" arch="i386"/>
  <component os="Linux"   path="libSuperI64.so" type="native" arch="x86_64"/>
</bundle>

Важно не перепутать содержание атрибута path! Заметили имя своего проекта в имени конечной библиотеки?

Теперь немного муторное дело - нужно подготовить последний магический файлик с именем SuperI.def в папке исходного кода <путь до>\Documents\Visual Studio 2013\ProjectsCPP\SuperI\SuperI

Содержимое файла (обратите внимание на имя SuperI):

LIBRARY    "SuperI"

EXPORTS
GetClassObject
DestroyObject
GetClassNames

В студии есть "Обозреватель решений". Обычно он даже открыт, но если Вы закрываете всё лишнее, то можно открыть его снова Вид\Обозреватель решений. В окне обозревателя решений в самом верху дерева указан проект, а ниже наше решение "SuperI". Пот по решению и щелкаем правой кнопкой (кнопка на мышке). В самом низу контекстного меню есть пункт "Свойства". Выбираем его.

В открывшемся окне слева опять дерево. Пропускаем "Общие свойства" и переходим "Свойства конфигурации\Компоновщик\Все параметры". В списке (в самом низу почти) есть пункт "Файл определения модуля". Он-то нам и нужен! Нужно изменить его значение на текст: SuperI.def

НАЖИМАЕМ КНОПКУ "OK".

Все, магия кончилась. 

На этом месте у Вас уже есть вполне рабочий инструмент - базовый компонент, который можно наследовать со своей реализацией. Пример такой реализации мы в начале добавим, а позже разберем.

Добавляем файл class.hpp в папку с исходными тестами <путь до>\Documents\Visual Studio 2013\ProjectsCPP\SuperI\SuperI

Теперь можно собрать проект  "Сборка\Собрать решение"

 

 У меня получился такой результат:

 

Это не значит, что у Вас то же самое. Но если получилось успешно собрать, то поздравляю!

Дальше идем в 1С и пишем там такой код:

&НаКлиенте   
перем ДемоКомп;

&НаКлиенте
Процедура ВнешнееСобытие(Источник, Событие, Данные)
	Сообщить(Источник + " " + Событие + " " + Данные);
КонецПроцедуры
&НаКлиенте
Процедура ПриОткрытии(Отказ)
	res=ПодключитьВнешнююКомпоненту("C:\Users\etyurin\Documents\Visual Studio 2013\ProjectsCPP\SuperI\Debug\SuperI.dll", "VK", ТипВнешнейКомпоненты.Native);
	ДемоКомп = Новый("AddIn.VK.myClass");
	ДемоКомп.Свойство_int=-59;
	ДемоКомп.Свойство_double=-10.6598;
	ДемоКомп.Свойство_pchar="увфцв sdfd 4545";
	врем=ДемоКомп.Свойство_pchar;
	ДемоКомп.Свойство_bool=Ложь;
	ДемоКомп.Свойство_tm=ТекущаяДата();
	ДемоКомп.Процедура1(-29);
	res=ДемоКомп.Функция2(-1,-9000);
	res2=ДемоКомп.Функция1();
КонецПроцедуры

Проверяйте работу в отладчике 1С.

Грабли:

1) Нет манифеста

2) Нет магического файла

3) Проект не библиотеки (просто поменяете в свойствах решения "свойства конфигурации\общие" - в списке "тип конфигурации" установите "Динамическая библиотека (.dll)", не забываем нажимать "Ok")

 

Теперь пришло время немного внимательней разобраться. Лучше сразу освоить отладку компоненты в студии. Меню "Отладка\Присоединиться к процессу"

Откроется список процессов, вызовы из которых можно перехватить:

 

 После этого на Ваших точках останова программа будет тормозиться. И можно выяснить в чем же проблема то.

Когда Вы пишете в 1С:

res=ПодключитьВнешнююКомпоненту("C:\Users\etyurin\Documents\Visual Studio 2013\ProjectsCPP\SuperI\Debug\SuperI.dll", "VK", ТипВнешнейКомпоненты.Native);

то первым делом будет запущена функция:

 

BOOL APIENTRY DllMain(HMODULE hModule,
					  DWORD  ul_reason_for_call,
					  LPVOID lpReserved
					  )

Что напряглись? Расслабьтесь в это вникать не нужно.

Как 1С узнает, что в компоненте присутствует? - Ответ 1С получит вызвав функцию GetClassNames():

/*Список доступных типов*/
static const wchar_t Class_Names[] = L"myClass"; //|OtherClass1|OtherClass2

/*Получение списка возможных типов*/
const WCHAR_T* GetClassNames() {
	static WCHAR_T* names;
	wchar_to_WCHAR(names, Class_Names);

	return names;
}
.

Class_Names - это просто массив символов, где через вертикальную черту перечислены все возможные имена классов или их псевдонимы. Функция GetClassNames просто возвращает в 1С эту строку.

1С будет создавать экземпляры каждого типа сразу при подключении, а потом будет использовать их. Если вызвать первый раз Новый("AddIn.VK.myClass"), то будет использован уже созданный при подключении экземпляр, а если вызвать снова Новый("AddIn.VK.myClass") - то будет создан уже новый экземпляр класса.

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

long GetClassObject(const WCHAR_T* ex_name, Base** pInterface) {
	if(!*pInterface) {
		wchar_t * name = nullptr;
		WCHAR_to_wchar(name, ex_name);
		if(!wcscmp(name, L"myClass"))
			*pInterface = new myClass();
		delete[] name;
		return (long)*pInterface;
	}
	return 0;
}

Функция GetClassObject устроена совсем примитивно - в ней указано соответствие между именем и классом. Она создает экземпляр и возвращает ссылку на него платформе.

Недостатком типового "решения" 1С является его ориентация не на быструю разработку, а на быстрое понимание принципов работы платформы с компонентой. Поэтому здесь Вы не найдете этого типового примера. 

Когда создается экземпляр класса, то вызывается его конструктор:

/*конструктор*/
	myClass() {
		/*объявляем имя класса доступное из 1С*/
		Base::fill_name(L"myClass");

		/*объявляем свойства доступные из 1С*/
		Base::Prop Props[] = {
			{L"Свойство_int"   , L"Prorp0", true, true},
		    {L"Свойство_double", L"Prorp1", true, true},
			{L"Свойство_pchar" , L"Prorp2", true, true},
			{L"Свойство_bool"  , L"Prorp3", true, true},
			{L"Свойство_tm"    , L"Prorp4", true, true}
		};
		Base::fill_props(Props, sizeof(Props) / sizeof(Base::Prop));

		/*объявляем методы доступные из 1С*/
		Base::Method Methods[] = {
			{L"Функция1", L"Func1", 0},
			{L"Функция2", L"Func2en", 2},
			{L"Процедура1", L"Proc1en", 1, true}
		};		
		Base::fill_methods(Methods, sizeof(Methods) / sizeof(Base::Method));
		
		Prop2 = new char[100];
		std::strcpy(Prop2, "abc абС 123");

		time_t rawtime;
		time(&rawtime);
		Prop4 = *localtime(&rawtime);		
	}

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

/*объявляем имя класса доступное из 1С*/
		Base::fill_name(L"myClass");

Платформа обязательно спросит его снова, и нам нужно не забыть вернуть то же наименование. Чтобы разобраться в назначение последующего кода нужно держать в голове схему опроса платформой возможностей экземпляра класса. Платформу будет интересовать количество доступных свойств (GetNProps). Зная количество 1С будет запрашивать свойства по их индексам (начиная с 0).  Имя свойства (GetPropName), можно ли прочитать значение свойства (IsPropReadable), можно ли изменить (IsPropWritable), получить значение свойства (GetPropVal) или установить значение (SetPropVal). Во всех этих случаях платформа будет передавать индекс. А вот тип значения 1С не беспокоит - вы получите коробку, в которой может быть сразу любой тип (Ваша компонента будет решать, что с этой коробкой делать).

/*объявляем свойства доступные из 1С*/
		Base::Prop Props[] = {
			{L"Свойство_int"   , L"Prorp0", true, true},
		        {L"Свойство_double", L"Prorp1", true, true},
			{L"Свойство_pchar" , L"Prorp2", true, true},
			{L"Свойство_bool"  , L"Prorp3", true, true},
			{L"Свойство_tm"    , L"Prorp4", true, true}
		};
		Base::fill_props(Props, sizeof(Props) / sizeof(Base::Prop));

В констукторе экземпляра заполняется массив структур Props. С каждым свойством связано два имени (русское и английское) и два свойства возможность получить значение и возможность изменить значение. Так они и перечислены:

{L"Русское_Имя", L"Английское_Имя", <возможность получить значение> , < возможность изменить значение>}

Аналогично обстоят дела и с функциями/процедурами. Также все методы вызываются по номерам:

/*объявляем методы доступные из 1С*/
		Base::Method Methods[] = {
			{L"Функция1", L"Func1", 0},
			{L"Функция2", L"Func2en", 2},
			{L"Процедура1", L"Proc1en", 1, true}
		};		
		Base::fill_methods(Methods, sizeof(Methods) / sizeof(Base::Method));

Требуется указать русское имя, английское, количество параметров и признак процедуры:

{L"Русское_Имя", L"Английское_Имя", <количество параметров> , <признак процедуры>}

Типы параметров платформу не интересуют. Она просто будет следить за нужным их количеством. Все параметры будут переданы массивом коробок, с указанием количества элементов в массиве. Если признак процедуры равен true, то возвращаемое значение в 1С передать не получится. 

Вот и весь конструктор, который требуется оформить.

Посмотрим на детали обращения к свойствам (с методами повторится тот же алгоритм). Когда в коде 1С мы пишем:

врем=ДемоКомп.Свойство_pchar;

то платформе понадобится номер свойства (ведь в коде только имя). Немедленно последует вызов функции FindProp:

long Base::FindProp(const WCHAR_T* ex_name) {
	long res = -1;
	wchar_t * temp = nullptr;
	WCHAR_to_wchar(temp, ex_name);
		
	for(long i = 0; res == -1 && i < cnt_props; ++i)
		if(!wcscmp(Props[i]->en, temp) || !wcscmp(Props[i]->ru, temp))
			res = i;
	
	delete[] temp;

	return res;
}

Эта функция просто вернет индекс свойства из массива Props (помните в конструкторе заполняли?) Получив индекс платформа будет выяснять возможность прочитать свойство IsPropReadable:

 

bool Base::IsPropReadable(const long num) {
	if(num < cnt_props)
		return Props[num]->r;
	else
		return false;
}

Функция просто вернет соответствующее поле структуры свойств Props. Если свойство можно прочитать, то от платформы последует вызов  GetPropVal:

 

/*Получение свойства*/
	virtual bool ADDIN_API GetPropVal(const long num, tVariant* var) override {
		switch(num) {
			case 0: //Свойство_int
				TV_VT(var) = VTYPE_I4; //выставляем тип
				TV_I4(var) = Prop0;    //выставляем значение
				break;
			case 1: //Свойство_double
				TV_VT(var) = VTYPE_R8;  //выставляем тип
				TV_R8(var) = Prop1;     //выставляем значение
				break;
			case 2: //Свойство_pchar
				TV_VT(var) = VTYPE_PSTR;  //выставляем тип
				var->pstrVal = Prop2;     //сразу указатель на строку
				var->strLen  = std::strlen(Prop2);
				break;
			case 3: //Свойство_bool
				TV_VT(var) = VTYPE_BOOL; //выставляем тип
				TV_BOOL(var) = Prop3;    //выставляем значение
				break;
			case 4: //Свойство_tm
				TV_VT(var) = VTYPE_TM; //выставляем тип
				var->tmVal = Prop4;    //выставляем значение
				break;
			default:
				return false;
		}
		return true;
	}

Функция заполняет коробку tVariant* согласно индекса переданного свойства. Сама коробка в деталях описана в types.h

Если в коде 1С написать:

ДемоКомп.Свойство_int=-59;

То последуют вызовы FindProp и IsPropWritable (можно ли изменять свойство):

 

bool Base::IsPropWritable(const long num) {
	if(num < cnt_props)
		return Props[num]->w;
	else
		return false;
}

Наша функция просто вернет соответствующее поле структуры Props, по указанному платформой индексу. Если свойство можно менять, то последует вызов SetPropVal с указанием индекса свойства:

 

/*Установка свойства*/
	virtual bool ADDIN_API SetPropVal(const long num, tVariant * var) override {
		switch(num) {
			case 0:
				if(TV_VT(var) != VTYPE_I4)
					return false;
				Prop0 = TV_I4(var);
				break;
			case 1:
				if(TV_VT(var) != VTYPE_R8)
					return false;
				Prop1 = TV_R8(var);
				break;
			case 2:
				if(TV_VT(var) == VTYPE_PSTR) { 
					delete[] Prop2;
					size_t len = std::strlen(var->pstrVal);
					Prop2 = new char[len + 1];
					std::strncpy(Prop2, var->pstrVal, len + 1);
					break;
				} else if(TV_VT(var) == VTYPE_PWSTR) {
					delete[] Prop2;
					WCHAR_to_char(Prop2, var->pwstrVal);
					break;
				} else
					return false;
			case 3:
				if(TV_VT(var) != VTYPE_BOOL)
					return false;
				Prop3 = TV_BOOL(var);
				break;
			case 4:
				if(TV_VT(var) != VTYPE_TM)
					return false;
				Prop4 = var->tmVal;
				break;
			default:
				return false;
		}
		return true;
	}

 Платформа "любит" передавать строки через указатель WCHAR_T*

Ну что страшно пока? Ничего, скоро поймете, что самое страшное я за Вас сделал и Вам осталось только приятная часть. Кстати со свойствами больше ничего и нет. Они перечислены как члены данных в классе:

private:
	int     Prop0 = -113; 
	double  Prop1 = 7.65;
	char  * Prop2 = nullptr;
	bool    Prop3 = true;
	tm      Prop4;

 Полегчало?

Вы можете просто написать такой класс:

class myClass: public Base {
public:
	/*конструктор*/
	myClass() {
		/*объявляем имя класса доступное из 1С*/
		Base::fill_name(L"myClass");
        }
};

и экземпляр его уже можно создать  строчкой:

ДемоКомп = Новый("AddIn.VK.myClass");

только он совсем пустой и ничего не делает.

Пришла пора взглянуть на методы. Это процедуры и функции. Сведения о них платформа получает последовательно. В начале - общее количество всех методов GetNMethods, потом количество формальных параметров конкретного метода GetNParams (просто по индексу, как обычно), дальше платформа захочет выяснить нужно ли ей принимать возвращаемое значение HasRetVal. И в конце последует вызов метода CallAsProc (для процедуры) или CallAsFunc(для функции). Вот смотрите пример:

/*Методы*/
	virtual       bool     ADDIN_API CallAsProc(const long num, tVariant* paParams, const long len) override {
		bool res = false;
		if(num < cnt_methods && Methods[num]->is_proc) {
			switch(num) {
				case 2:
					res = Proc1(paParams, len);
					break;
				default:
					res = false;
			}
		}
		return res; 
	} 
	virtual       bool     ADDIN_API CallAsFunc(const long num, tVariant* pvarRetValue, tVariant* paParams, const long len) override {
		bool res = false;
		if(num < cnt_methods && !Methods[num]->is_proc) {
			switch(num) {
				case 0:
					res = Func1(pvarRetValue, paParams, len);
					break;
				case 1:
					res = Func2(pvarRetValue, paParams, len);
					break;		
				default:
					res = false;
			}
		}
		return res;		
	} 

	bool Proc1(tVariant* paParams, const long lSizeArray) {
		bool res = true;
		if(paParams[0].vt == VTYPE_I4) //Проверка, что пришло целое число
			this->Prop0 = paParams[0].lVal; //значение
		else
			res = false;
		return res; 
	}
	bool Func2(tVariant* pvarRetValue, tVariant* paParams, const long len) {
		bool res = true;
		int a,b;
		if(paParams[0].vt == VTYPE_I4) //Проверка, что пришло целое число
			a = paParams[0].lVal; //значение
		else
			res = false;
		if(paParams[1].vt == VTYPE_I4) //Проверка, что пришло целое число
			b=paParams[1].lVal; //значение
		else
			res = false;
		
		if(res) {
			pvarRetValue->vt = VTYPE_I4; //указываем возвращаемый тип
			pvarRetValue->lVal = a + b;  //указываев возвращаемое значение (выполнять pMemoryAdapter->AllocMemory((void**)&pvarRetValue->lVal, size_in_byte) здесь не требуется, т.к. передаем значение) 
		}

		return res; 
	}
	bool Func1(tVariant* pvarRetValue, tVariant* paParams, const long len) {
		bool res = true;
		size_t l = std::strlen(Prop2) + 1;
		pvarRetValue->vt = VTYPE_PSTR;
		pvarRetValue->strLen = l;
		/*нужно аллоцировать место в структуре возвращаемой в 1С*/
		pMemoryAdapter->AllocMemory((void**)&pvarRetValue->pstrVal, l*sizeof(char));
		std::memcpy(pvarRetValue->pstrVal, Prop2, l*sizeof(char));

		return res;
	}

Платформа передает индекс метода, коробку с параметрами и количество элементов в коробке. Вам не нужно беспокоиться о количестве элементов (будет ровно столько, сколько вы указали в конструкторе). А вот с выковыриванием нужных Вам значений из коробок придется постараться. Для этого обязательно выясняйте значение поля vt, чтоб знать как извлечь значение.

Как только в 1С переменная ДемоКомп покинет границы видимости, сразу последует вызов DestroyObject:

/*Уничтожение экземпляра*/
long DestroyObject(Base** pIntf) {
	if(!*pIntf)
		return -1;

	delete *pIntf;
	*pIntf = 0;
	return 0;
}

Платформа так сообщает компоненте, что экземпляр больше не нужен.

Заметили, что компонента с типом Native не требует регистрации? 

Скачать файлы

Наименование Файл Версия Размер
Конструктор

.7z 9,20Kb
0
.7z 2 9,20Kb Скачать

Специальные предложения

Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. DoctorRoza 14.03.16 13:45 Сейчас в теме
Для полной ясности как такое работает, нужен хороший пример! Например, реализуйте компоненту, которая делает задержку выполнения кода или, скажем, цикла. Мне как-то такое потребовалось, не помню зачем.
2. ture 580 14.03.16 14:01 Сейчас в теме
(1) DoctorRoza, Не вопрос!
Сейчас работаю над простой реализацией. У Вас будет простой вариант наследования базового компонента, а вся рутина будет реализована в базовом классе. Опишу порядок взаимодействия с 1С в той мере, в которой это будет полезно конечному разработчику.
DoctorRoza; +1 Ответить
3. Evil Beaver 7013 14.03.16 15:22 Сейчас в теме
А какие преимущества указанного способа по сравнению с шаблоном проекта C++ и методикой "Разработки внешних компонент" с диска ИТС?

Например, я (как пользователь инфостарта) могу взять шаблон проекта и методику вот отсюда http://infostart.ru/public/184119/. Чем ваш вариант отличается от предлагаемого на ИТС?

Мне просто не хочется тратить 10sm, чтобы всего лишь выяснить разницу.
avz_1C; vdgb_bushkov; +2 1 Ответить
4. ture 580 14.03.16 17:12 Сейчас в теме
(3) Evil Beaver, В чем преимущество моего варианта перед Вашим? Ну... во-первых, я потерял дар речи...
Я опирался на Ваше описание!!! Нету преимущества здесь.

Ладно, по сути дела. Для меня оказалось неожиданностью такое внимание к "создать проект библиотеки DLL в студии" (это ведь черновой вариант по моим понятиям). Даже появилась задумка "создать проект консольного приложения (в картинках ;)"

На диске ИТС лежит готовый проект. И что мало кто знает, как создать его с 0? В общем, это может объяснить популярность.

Я столкнулся с тем, что проект на ИТС написан ровно для того, чтобы быстро разобраться как и что. Но он не может служить основой реальной разработки. Я решил исправить недочет и стал выкладывать решение последовательно. В какой-то момент свое решение я стал переписывать в третий раз и уже с учетом большинства своих хочу. Но версию с фрагментами ИТС решил выложить, чтоб не пропадало. Сейчас я готовлю рабочий проект с базовым классом, который удобно и просто наследовать (собственно пишу с самого начала для себя, чтоб удобней было быстро стартовать).
10. Evil Beaver 7013 15.03.16 13:33 Сейчас в теме
(4) ture, нет никакого "моего" варианта. Я просто документировал тот шаблон, который лежит на ИТС.
А вопрос мой был про то - что из статьи непонятно, что именно лежит в архиве. Отличается ли оно от ИТС-ного шаблона и в какую сторону.
11. ture 580 15.03.16 14:34 Сейчас в теме
(10) Evil Beaver, в архиве просто компоненты использованные в статье:
adapter.h
memory_adapter.h
base.h
com.h
types.h
SuperI.def
MANIFEST.XML

Эти файлы наиболее близки к тому, что на ИТС. Шаблон 1С весьма своеобразен. Особенно порадовал базовый класс корпорации.
Вы документировали механизм взаимодействия 1с со своими компонентами ;) Я уже третий день рою эту тему... уже владею основами. Сейчас усердно протираю глаза и пытаюсь понять "как это нельзя массив передать в native dll?! шел год 2016"

Я не добавлял в архив человеческую реализацию базового класса, который можно легко наследовать. Я только работаю над ним, но что-то выложил в комментариях уже.
21. Synoecium 718 16.03.16 06:27 Сейчас в теме
(3) Evil Beaver, Ваша статья идеально подходит для новичков, которым надо разобраться как создавать внешние компоненты. Здесь же написан какой-то сумбур. Вроде я понимаю о чем речь, но как то смутно, при этом я сам ковырялся с внешними компонентами. В общем автору пока минус, в надежде на то, что он выложит волшебный класс, про который много говорит. За что 10 sm вообще не понятно.
22. ture 580 16.03.16 08:51 Сейчас в теме
(21) Synoecium, всегда приятно читать такие комменты, они расслабляют и позволяют не напрягаться. Компонент я выложил в своих комментах.
5. ture 580 15.03.16 10:47 Сейчас в теме
http://bb3x.ru/blog/vneshnie-komponentyi-v-1s-8-2/
Вы намереваетесь использовать пример от 1С. Я дополнил его комментариями.
Немного поясню детали стандартной реализации:
1) 1С вызовет GetClassNames(), что бы узнать список возможных классов (в примере 1С он один)
2) 1С создаст экземпляр каждого из возможных классов (в GetClassObject будет передавать имена классов последовательно, сразу все и создает)
3) 1С инициализирует каждый класс Init, setMemManager, SetLocale (последний на случай, если компонента умеет на разных языках отвечать)
4) 1С спросит версию у каждого класса GetInfo и выяснит его имя RegisterExtensionAs (для строки Новый("AddIn.VK.ture"))
Дальше все стихнет, пока не появится следующий код (вызов методов и свойств)
Свойства:
1) В начале 1С будет выяснять сколько всего свойств в конкретном классе GetNProps
2) Потом будет получать имя каждого свойства по номеру GetPropName (последний параметр - рус или en)
3) Если 1С встречает в коде свойство, то вызывает FindProp (чтоб узнать номер свойства), потом IsPropReadable (чтоб узнать, можно ли его читать) или IsPropWritable (чтоб выяснить, можно ли писать в него). В финале вызывается GetPropVal (для чтения свойства, зная его порядковый номер) или SetPropVal (для записи)
С функциями то же самое. Это рефлексия типов такая у 1С.

Значения передаются через структуру _tVariant. У нее есть тип vt и куча значений в union (заполнено осмыслено какое-то одно).
/*Получение свойства*/
	virtual bool ADDIN_API GetPropVal(const long num, tVariant* var) override {
		switch(num) {
			case 0: //Свойство_int
				TV_VT(var) = VTYPE_I4; //выставляем тип
				TV_I4(var) = Prop0;    //выставляем значение
				break;
			case 1: //Свойство_double
				TV_VT(var) = VTYPE_R8;  //выставляем тип
				TV_R8(var) = Prop1;     //выставляем значение
				break;
			case 2: //Свойство_pchar
				TV_VT(var) = VTYPE_PSTR;  //выставляем тип
				var->pstrVal = Prop2;     //сразу указатель на строку
				var->strLen  = std::strlen(Prop2);
				break;
			case 3: //Свойство_bool
				TV_VT(var) = VTYPE_BOOL; //выставляем тип
				TV_BOOL(var) = Prop3;    //выставляем значение
				break;
			case 4: //Свойство_tm
				TV_VT(var) = VTYPE_TM; //выставляем тип
				var->tmVal = Prop4;    //выставляем значение
				break;
			default:
				return false;
		}
		return true;
	}
	/*Установка свойства*/
	virtual bool ADDIN_API SetPropVal(const long num, tVariant * var) override {
		switch(num) {
			case 0:
				if(TV_VT(var) != VTYPE_I4)
					return false;
				Prop0 = TV_I4(var);
				break;
			case 1:
				if(TV_VT(var) != VTYPE_R8)
					return false;
				Prop1 = TV_R8(var);
				break;
			case 2:
				if(TV_VT(var) == VTYPE_PSTR) { 
					delete[] Prop2;
					size_t len = std::strlen(var->pstrVal);
					Prop2 = new char[len + 1];
					std::strncpy(Prop2, var->pstrVal, len + 1);
					break;
				} else if(TV_VT(var) == VTYPE_PWSTR) {
					delete[] Prop2;
					WCHAR_to_char(Prop2, var->pwstrVal);
					break;
				} else
					return false;
			case 3:
				if(TV_VT(var) != VTYPE_BOOL)
					return false;
				Prop3 = TV_BOOL(var);
				break;
			case 4:
				if(TV_VT(var) != VTYPE_TM)
					return false;
				Prop4 = var->tmVal;
				break;
			default:
				return false;
		}
		return true;
	} 
Показать
6. ture 580 15.03.16 11:05 Сейчас в теме
В примере выше я использовал функции:
/*Конвертация wchar_t* -> WCHAR_T* */
size_t wchar_to_WCHAR(WCHAR_T * &Dest, const wchar_t* Source, size_t len) {
	if(len == 0) {//если размер задан, то и место уже зарезервировано
		len = wchar_len(Source) + 1;
		Dest = new WCHAR_T[len];
	}
	memset(Dest, 0, len*sizeof(WCHAR_T));	
	for(size_t i = 0; i < len && Source[i]; ++i)
		Dest[i] = (WCHAR_T)Source[i];			

	return len;
}
/*Конвертация wchar_t* -> char* */
size_t wchar_to_char(char * &Dest, const wchar_t* Source, size_t len) {
	if(len == 0) {//если размер задан, то и место уже зарезервировано
		len = wchar_len(Source) + 1;
		Dest = new char[len];
	}
	len = wcstombs(Dest, Source, len);
	Dest[len - 1] = '\0';
	return len;
}
/*Конвертация WCHAR_T** -> wchar_t* */
size_t WCHAR_to_wchar(wchar_t * &Dest, const WCHAR_T* Source, size_t len) {
	if(len==0){//если размер задан, то и место уже зарезервировано
		len = WCHAR_len(Source) + 1;
		Dest = new wchar_t[len];
	}
	memset(Dest, 0, len*sizeof(wchar_t));
	for(size_t i = 0; i < len && Source[i]; ++i)
		Dest[i] = (wchar_t)Source[i];

	return len;
}
/*Конвертация WCHAR_T** -> char* */
size_t WCHAR_to_char(char * &Dest, const WCHAR_T* Source, size_t len) {
	wchar_t * temp;
	WCHAR_to_wchar(temp, Source);
	len=wchar_to_char(Dest, temp,len);
	delete[] temp;

	return len;
}
/*Вычисление длинны строки WCHAR_T* */
size_t WCHAR_len(const WCHAR_T* Source) {
	size_t res = 0;
	while(Source[res]) 	++res;

	return res;
}
/*Вычисление длинны строки wchar_t* */
size_t wchar_len(const wchar_t* Source) {
	size_t res = 0;
	while(Source[res]) 	++res;

	return res;
}

Показать
7. ture 580 15.03.16 11:07 Сейчас в теме
1С создает экземпляры сразу:
/*Список доступных типов (регистрируются в RegisterExtensionAs тем же именем)*/
static const wchar_t Class_Names[] = L"myClass"; //|OtherClass1|OtherClass2

/*ЭКСПОРТИРУЕМЫЕ МЕТОДЫ*/
/*Получение экземпляра по имени*/
long GetClassObject(const WCHAR_T* ex_name, Base** pInterface) {
	if(!*pInterface) {
		wchar_t * name = nullptr;
		WCHAR_to_wchar(name, ex_name);
		if(!wcscmp(name, L"myClass"))
			*pInterface = new myClass();
		delete[] name;
		return (long)*pInterface;
	}
	return 0;
}
/*Получение списка возможных типов*/
const WCHAR_T* GetClassNames() {
	static WCHAR_T* names;
	wchar_to_WCHAR(names, Class_Names);

	return names;
}
Показать
8. ture 580 15.03.16 11:09 Сейчас в теме
Лучше использовать не пример от 1С, а свой базовый класс:
/***************************************************
*  Данный класс предназначен для наследования      *
****************************************************/
class Base:public IInitDoneBase, public ILanguageExtenderBase, public LocaleBase {
protected:
	/*вложенные типы (для "рефлексии типа из 1С")*/
	struct Prop {	
		wchar_t *ru, *en;
		bool    r,w;
		void Init(const wchar_t *ru, const wchar_t *en, bool r, bool w) {
			/*копируем имена свойств ru и en*/
			size_t len = wcslen(ru) + 1;
			this->ru = new wchar_t[len];
			memcpy(this->ru, ru, len*sizeof(wchar_t));
			len = wcslen(en) + 1;
			this->en = new wchar_t[len];
			memcpy(this->en, en, len*sizeof(wchar_t));
			/*копируем призначки чтения и записи*/
			this->r = r;
			this->w = w;
		}
		Prop(const wchar_t *ru, const wchar_t *en, bool r, bool w) {
			Init(ru, en, r, w);
		}
		Prop(const Prop & other) {
			Init(other.ru, other.en, other.r, other.w);
		}
		~Prop() {
			delete[] ru, en;
			ru = en = nullptr;
		}
	};
	struct Method {
		wchar_t *ru, *en;
		bool    is_proc;
		void Init(const wchar_t *ru, const wchar_t *en, bool is_proc) {
			/*копируем имена методов ru и en*/
			size_t len = wcslen(ru) + 1;
			this->ru = new wchar_t[len];
			memcpy(this->ru, ru, len*sizeof(wchar_t));
			len = wcslen(en) + 1;
			this->en = new wchar_t[len];
			memcpy(this->en, en, len*sizeof(wchar_t));
			/*копируем признак процедуры*/
			this->is_proc = is_proc;
		}
		Method(const wchar_t *ru, const wchar_t *en, bool is_proc) {
			Init(ru, en, is_proc);
		}
		Method(const Method & other) {
			Init(other.ru, other.en, other.is_proc);
		}
		~Method() {
			delete[] ru, en;
			ru = en = nullptr;
		}
	};
	
	/*адаптеры*/
	Adapter            * pAdapter;
	MemoryAdapter      * pMemoryAdapter;
	
	/*Локальное имя*/
	wchar_t * name;
	/*свойства, методы и классы*/
	long cnt_props;
	Prop ** Props;	
	long cnt_methods;
	Method ** Methods;
	/*заполнение свойств и методов*/
	void fill_name(const wchar_t * name);
	void fill_props(const Prop * Prors = nullptr, long cnt_props = 0);
	void fill_methods(const Method * Methods = nullptr, long cnt_methods = 0);
		
	virtual void addError(uint32_t wcode, const wchar_t* source, const wchar_t* descriptor, long code);

public:
	/*Деструктор*/
	virtual ~Base();
	/*Конструктор*/
	Base():cnt_props(0), Props(nullptr), cnt_methods(0), Methods(nullptr), pAdapter(nullptr), pMemoryAdapter(nullptr), name(nullptr) {}

	/*Инициализация и завершение*/
	virtual bool ADDIN_API Init(void*)                   override;
	virtual bool ADDIN_API setMemManager(void* mem)      override;
	virtual long ADDIN_API GetInfo()                     override;
	virtual void ADDIN_API Done()                        override;
	/*смена локализации*/
	virtual void ADDIN_API SetLocale(const WCHAR_T* loc) override;

	/*Расширение языка*/
	/*Регистрация расширения под конкретным именем*/
	virtual       bool     ADDIN_API RegisterExtensionAs(WCHAR_T**) override;

	virtual       long     ADDIN_API GetNProps() override  { return cnt_props; }
	virtual       long     ADDIN_API FindProp(const WCHAR_T* wsPropName) override;
	virtual const WCHAR_T* ADDIN_API GetPropName(long lPropNum, long lPropAlias) override;
	virtual       bool     ADDIN_API IsPropReadable(const long lPropNum) override;
	virtual       bool     ADDIN_API IsPropWritable(const long lPropNum) override;
	virtual       bool     ADDIN_API GetPropVal(const long num, tVariant* var) override { return false; } //заглушка на случай отсутствия свойств
	virtual       bool     ADDIN_API SetPropVal(const long num, tVariant* val) override { return false; } //заглушка на случай отсутствия свойств
	
	virtual       long     ADDIN_API GetNMethods() override  { return cnt_methods; }
	virtual       long     ADDIN_API FindMethod(const WCHAR_T* wsMethodName) override;
	virtual const WCHAR_T* ADDIN_API GetMethodName(const long lMethodNum, const long lMethodAlias) override;
	virtual       long     ADDIN_API GetNParams(const long lMethodNum) override { return 0; }                                                                        //заглушка на случай отсутствия методов
	virtual       bool     ADDIN_API GetParamDefValue(const long lMethodNum, const long lParamNum, tVariant *pvarParamDefValue) override  { return false; }          //заглушка на случай отсутствия методов
	virtual       bool     ADDIN_API HasRetVal(const long lMethodNum) override;	
	virtual       bool     ADDIN_API CallAsProc(const long lMethodNum, tVariant* paParams, const long lSizeArray) override { return false; };                        //заглушка на случай отсутствия методов
	virtual       bool     ADDIN_API CallAsFunc(const long lMethodNum, tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray) override { return false; } //заглушка на случай отсутствия методов
};
Показать
9. ture 580 15.03.16 11:11 Сейчас в теме
Свой класс становится проще при повторном использовании:
#include "base.h"
#include <ctime>

#ifndef CLASS_H
#define CLASS_H

class myClass: public Base {
private:
	int     Prop0 = -113; 
	double  Prop1 = 7.65;
	char  * Prop2 = nullptr;
	bool    Prop3 = true;
	tm      Prop4;
public:
	/*конструктор*/
	myClass() {
		/*объявляем имя класса доступное из 1С*/
		Base::fill_name(L"myClass");

		/*объявляем свойства доступные из 1С*/
		Base::Prop Props[] = {
			{L"Свойство_int"   , L"Prorp0", true, true},
		    {L"Свойство_double", L"Prorp1", true, true},
			{L"Свойство_pchar" , L"Prorp2", true, true},
			{L"Свойство_bool"  , L"Prorp3", true, true},
			{L"Свойство_tm"    , L"Prorp4", true, true}
		};
		Base::fill_props(Props, sizeof(Props) / sizeof(Base::Prop));

		/*объявляем методы доступные из 1С*/
		Base::Method Methods[] = {
			{L"Функция1", L"Func1", false},
		    {L"Функция2", L"Func2", false},
		    {L"Процедура1", L"Proc1", true}
		};
		Base::fill_methods(Methods, sizeof(Methods) / sizeof(Base::Method));

		Prop2 = new char[100];
		std::strcpy(Prop2, "abc абС 123");

		time_t rawtime;
		time(&rawtime);
		Prop4 = *localtime(&rawtime);		
	}
	~myClass() { 
		delete[] Prop2; 		
	}
	
	/*Получение свойства*/
	virtual bool ADDIN_API GetPropVal(const long num, tVariant* var) override {
		switch(num) {
			case 0: //Свойство_int
				TV_VT(var) = VTYPE_I4; //выставляем тип
				TV_I4(var) = Prop0;    //выставляем значение
				break;
			case 1: //Свойство_double
				TV_VT(var) = VTYPE_R8;  //выставляем тип
				TV_R8(var) = Prop1;     //выставляем значение
				break;
			case 2: //Свойство_pchar
				TV_VT(var) = VTYPE_PSTR;  //выставляем тип
				var->pstrVal = Prop2;     //сразу указатель на строку
				var->strLen  = std::strlen(Prop2);
				break;
			case 3: //Свойство_bool
				TV_VT(var) = VTYPE_BOOL; //выставляем тип
				TV_BOOL(var) = Prop3;    //выставляем значение
				break;
			case 4: //Свойство_tm
				TV_VT(var) = VTYPE_TM; //выставляем тип
				var->tmVal = Prop4;    //выставляем значение
				break;
			default:
				return false;
		}
		return true;
	}
	/*Установка свойства*/
	virtual bool ADDIN_API SetPropVal(const long num, tVariant * var) override {
		switch(num) {
			case 0:
				if(TV_VT(var) != VTYPE_I4)
					return false;
				Prop0 = TV_I4(var);
				break;
			case 1:
				if(TV_VT(var) != VTYPE_R8)
					return false;
				Prop1 = TV_R8(var);
				break;
			case 2:
				if(TV_VT(var) == VTYPE_PSTR) { 
					delete[] Prop2;
					size_t len = std::strlen(var->pstrVal);
					Prop2 = new char[len + 1];
					std::strncpy(Prop2, var->pstrVal, len + 1);
					break;
				} else if(TV_VT(var) == VTYPE_PWSTR) {
					delete[] Prop2;
					WCHAR_to_char(Prop2, var->pwstrVal);
					break;
				} else
					return false;
			case 3:
				if(TV_VT(var) != VTYPE_BOOL)
					return false;
				Prop3 = TV_BOOL(var);
				break;
			case 4:
				if(TV_VT(var) != VTYPE_TM)
					return false;
				Prop4 = var->tmVal;
				break;
			default:
				return false;
		}
		return true;
	}

};

#endif
Показать

Я еще работаю над приятном видом. Что-то будет меняться.
12. TSSV 1058 15.03.16 18:24 Сейчас в теме
"Я не добавлял в архив человеческую реализацию базового класса, который можно легко наследовать." Как использовать скачанный архив, посоветуйте пожалуйста.
13. ture 580 15.03.16 18:52 Сейчас в теме
(12) TSSV, это dllmain.cpp
// dllmain.cpp : Defines the entry point for the DLL application.
#include "Base.h"
#include "class.hpp"

#ifndef __linux__
#include <windows.h>
#endif //__linux__
#ifndef __linux__
BOOL APIENTRY DllMain(HMODULE hModule,
					  DWORD  ul_reason_for_call,
					  LPVOID lpReserved
					  ) {
	switch(ul_reason_for_call) {
		case DLL_PROCESS_ATTACH:
		case DLL_THREAD_ATTACH:
		case DLL_THREAD_DETACH:
		case DLL_PROCESS_DETACH:
			break;
	}
	return TRUE;
}
#endif //__linux__

/*ПРОЧИЕ МЕТОДЫ*/
/*Конвертация wchar_t* -> WCHAR_T* */
size_t wchar_to_WCHAR(WCHAR_T * &Dest, const wchar_t* Source, size_t len) {
	if(len == 0) {//если размер задан, то и место уже зарезервировано
		len = wchar_len(Source) + 1;
		Dest = new WCHAR_T[len];
	}
	memset(Dest, 0, len*sizeof(WCHAR_T));	
	for(size_t i = 0; i < len && Source[i]; ++i)
		Dest[i] = (WCHAR_T)Source[i];			

	return len;
}
/*Конвертация wchar_t* -> char* */
size_t wchar_to_char(char * &Dest, const wchar_t* Source, size_t len) {
	if(len == 0) {//если размер задан, то и место уже зарезервировано
		len = wchar_len(Source) + 1;
		Dest = new char[len];
	}
	len = wcstombs(Dest, Source, len);
	Dest[len - 1] = '\0';
	return len;
}
/*Конвертация WCHAR_T** -> wchar_t* */
size_t WCHAR_to_wchar(wchar_t * &Dest, const WCHAR_T* Source, size_t len) {
	if(len==0){//если размер задан, то и место уже зарезервировано
		len = WCHAR_len(Source) + 1;
		Dest = new wchar_t[len];
	}
	memset(Dest, 0, len*sizeof(wchar_t));
	for(size_t i = 0; i < len && Source[i]; ++i)
		Dest[i] = (wchar_t)Source[i];

	return len;
}
/*Конвертация WCHAR_T** -> char* */
size_t WCHAR_to_char(char * &Dest, const WCHAR_T* Source, size_t len) {
	wchar_t * temp;
	WCHAR_to_wchar(temp, Source);
	len=wchar_to_char(Dest, temp,len);
	delete[] temp;

	return len;
}
/*Вычисление длинны строки WCHAR_T* */
size_t WCHAR_len(const WCHAR_T* Source) {
	size_t res = 0;
	while(Source[res]) 	++res;

	return res;
}
/*Вычисление длинны строки wchar_t* */
size_t wchar_len(const wchar_t* Source) {
	size_t res = 0;
	while(Source[res]) 	++res;

	return res;
}


/*Список доступных типов*/
static const wchar_t Class_Names[] = L"myClass"; //|OtherClass1|OtherClass2

/*ЭКСПОРТИРУЕМЫЕ МЕТОДЫ*/
/*Получение экземпляра по имени (регистрируются в RegisterExtensionAs тем же именем)*/
long GetClassObject(const WCHAR_T* ex_name, Base** pInterface) {
	if(!*pInterface) {
		wchar_t * name = nullptr;
		WCHAR_to_wchar(name, ex_name);
		if(!wcscmp(name, L"myClass"))
			*pInterface = new myClass();
		delete[] name;
		return (long)*pInterface;
	}
	return 0;
}
/*Уничтожение экземпляра*/
long DestroyObject(Base** pIntf) {
	if(!*pIntf)
		return -1;

	delete *pIntf;
	*pIntf = 0;
	return 0;
}
/*Получение списка возможных типов*/
const WCHAR_T* GetClassNames() {
	static WCHAR_T* names;
	wchar_to_WCHAR(names, Class_Names);

	return names;
}
Показать


Это base.h
/* Тута не писать! */

#ifndef BASE_H
#define BASE_H
#define _CRT_SECURE_NO_WARNINGS


#include "adapter.h"
#include "memory_adapter.h" 
#include "types.h" 
#include <cstring>
#include <functional>
using namespace std::placeholders;

/*интерфейс для инициализации компоненты (абстрактный класс)*/
class IInitDoneBase {
public:
	/*деструктор*/
	virtual ~IInitDoneBase() {}


	/* Инициализация
	*  @param disp - 1C:Enterpise interface
	*  @return the result of */
	virtual bool ADDIN_API Init(void* disp) = 0;


	/* Умтановка менеджера памяти
	*  @param mem - указатель на интерфейс менеджера памяти
	*  @return the result of */
	virtual bool ADDIN_API setMemManager(void* mem) = 0;


	/* Возврат версии компоненты
	*  @return - component version (2000 - это версия 2) */
	virtual long ADDIN_API GetInfo() = 0;


	/* Завершение работы компоненты.
	* Освобождение ресурсов.  */
	virtual void ADDIN_API Done() = 0;
};


/* Предопределенный интерфейс описания методов предназначенный для использования платформой 1С.
*  Интерфейс описывает расширение языка 1С*/
class ILanguageExtenderBase {
public:
	/*Деструктор*/
	virtual ~ILanguageExtenderBase() {}

	/* Имя класса в 1С
	*  @param ex_name - имя
	*  @return the result of  */
	virtual bool ADDIN_API RegisterExtensionAs(WCHAR_T** ex_name) = 0;

	/*==== СВОЙСТВА ====*/
	/* Возврат количества свойств класса, доступных из 1С
	*  @return количество свойств */
	virtual long ADDIN_API GetNProps() = 0;

	/* Определение номера свойства по имени
	*  @param ex_name - имя свойсва
	*  @return индекс свойства или -1, если не найдено */
	virtual long ADDIN_API FindProp(const WCHAR_T* ex_name) = 0;

	/* Возврат имени свойства по индексу
	*  @param num        - индекс свойства (начиная с 0)
	*  @param cur_locale - 0 - английское имя (обязательно должны быть),
	*                      1 - русское имя.
	*  @return имя свойства или 0, если не найдено */
	virtual const WCHAR_T* ADDIN_API GetPropName(long num, long cur_locale) = 0;

	/* Возврат значения свойства
	*  @param num - индекс свойства (начиная с 0)
	*  @param val - указатель на variable со значение свойства
	*  @return the result of   */
	virtual bool ADDIN_API GetPropVal(const long num, tVariant* val) = 0;

	/* Установка значения свойства
	*  @param num - индекс свойства (начиная с 0)
	*  @param val - указатель на variable хранящий новое значение
	*  @return the result of */
	virtual bool ADDIN_API SetPropVal(const long num, tVariant* val) = 0;

	/* Проверка возможности чтения значения свойсва
	*  @param num - индекс свойства (начиная с 0)
	*  @return true, если свойсво можно читать  */
	virtual bool ADDIN_API IsPropReadable(const long num) = 0;

	/* Проверка возможности изменять значение свойства
	*  @param num - индекс свойства (начиная с 0)
	*  @return true, если свойство можно изменить */
	virtual bool ADDIN_API IsPropWritable(const long num) = 0;


	/*==== МЕТОДЫ ====*/
	/* Возврат количества методов класса, доступных из 1С
	*  @return количество методов */
	virtual long ADDIN_API GetNMethods() = 0;

	/* Поиск метода по имени
	*  @param ex_name - имя метода
	*  @return             - индекс метода или -1, если не найдено  */
	virtual long ADDIN_API FindMethod(const WCHAR_T* ex_name) = 0;

	/* Возврат имени метода по индексу
	*  @param num        - индекс метода (начиная с 0)
	*  @param cur_locale - 0 - английское имя (обязательно должны быть),
	*                      1 - русское имя.
	*  @return имя метода или 0, если не найдено  */
	virtual const WCHAR_T* ADDIN_API GetMethodName(const long num, const long cur_locale) = 0;

	/* Возврат количества аргументов метода
	*  @param num - индекс метода (начиная с 0)
	*  @return количество аргументов  */
	virtual long ADDIN_API GetNParams(const long num) = 0;

	/* Возвращает значения поумолчанию аргументов метода
	*  @param lMethodNum - индекс метода (начиная с 0)
	*  @param lParamNum  - индекс параметра (начиная с 0)
	*  @param pvarParamDefValue - указатель на variable со значением поумолчанию
	*  @return the result of  */
	virtual bool ADDIN_API GetParamDefValue(const long lMethodNum, const long lParamNum, tVariant *pvarParamDefValue) = 0;

	/* Возвращает ли метод значение
	*  @param num - индекс метода (начиная с 0)
	*  @return true, если метод имеет возвращаемое значение */
	virtual bool ADDIN_API HasRetVal(const long num) = 0;

	/* Вызов метода без возвращаемого значения
	*  @param lMethodNum - индекс метода (начиная с 0)
	*  @param paParams   - указатель на массив аргументов метода
	*  @param lSizeArray - размер массива
	*  @return the result of   */
	virtual bool ADDIN_API CallAsProc(const long lMethodNum, tVariant* paParams, const long lSizeArray) = 0;

	/* Вызов метода с возвращаемым значением
	*  @param lMethodNum   - индекс метода (начиная с 0)
	*  @param pvarRetValue - указатель на возвращаемое значение
	*  @param paParams     - указатель на массив аргументов метода
	*  @param lSizeArray   - размер массива
	*  @return the result of  */
	virtual bool ADDIN_API CallAsFunc(const long lMethodNum, tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray) = 0;
};


/* Интерфейс используется, для изменения локализации в компоненте */
class LocaleBase {
public:
	/*Деструктор*/
	virtual ~LocaleBase() {}

	/* Изменение локализации
	*  @param loc - новая локаль (для Windows - rus_RUS, для Linux - ru_RU, и т.п...)   */
	virtual void ADDIN_API SetLocale(const WCHAR_T* loc) = 0;
};


/***************************************************
*  Данный класс предназначен для наследования      *
****************************************************/
class Base:public IInitDoneBase, public ILanguageExtenderBase, public LocaleBase {
protected:
	/*вложенные типы (для "рефлексии типа из 1С")*/
	struct Prop {	
		wchar_t *ru, *en;
		bool    r,w;
		void Init(const wchar_t *ru, const wchar_t *en, bool r, bool w) {
			/*копируем имена свойств ru и en*/
			size_t len = wcslen(ru) + 1;
			this->ru = new wchar_t[len];
			memcpy(this->ru, ru, len*sizeof(wchar_t));
			len = wcslen(en) + 1;
			this->en = new wchar_t[len];
			memcpy(this->en, en, len*sizeof(wchar_t));
			/*копируем призначки чтения и записи*/
			this->r = r;
			this->w = w;
		}
		Prop(const wchar_t *ru, const wchar_t *en, bool r, bool w) {
			Init(ru, en, r, w);
		}
		Prop(const Prop & other) {
			Init(other.ru, other.en, other.r, other.w);
		}
		~Prop() {
			delete[] ru, en;
			ru = en = nullptr;
		}
	};
	struct Method {
		typedef bool(_stdcall *func_t)(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray);
		typedef bool(_stdcall *proc_t)(tVariant* paParams, const long lSizeArray);
		wchar_t *ru, *en;
		bool    is_proc;
		short   cnt;

		func_t func; //указатель на функцию
		proc_t proc; //указатель на процедуру

		void Init(const wchar_t *ru, const wchar_t *en, func_t func, proc_t proc, short cnt, bool is_proc) {
			/*копируем имена методов ru и en*/
			size_t len = wcslen(ru) + 1;
			this->ru = new wchar_t[len];
			memcpy(this->ru, ru, len*sizeof(wchar_t));
			len = wcslen(en) + 1;
			this->en = new wchar_t[len];
			memcpy(this->en, en, len*sizeof(wchar_t));
			/*копируем указатели на функию и процедуру*/
			this->func = func;
			this->proc = proc;
			/*копируем количество параметров*/
			this->cnt = cnt;
			/*копируем признак процедуры*/
			this->is_proc = is_proc;
			
		}
		Method(const wchar_t *ru, const wchar_t *en, void * func, void * proc = nullptr, short cnt = 0, bool is_proc = false) {
			Init(ru, en, func != nullptr ? *(Base::Method::func_t*)func : nullptr, proc!=nullptr ? *(Base::Method::proc_t*)proc : nullptr, cnt, is_proc);
		}
		Method(const Method & other) {
			Init(other.ru, other.en, other.func, other.proc, other.cnt, other.is_proc);
		}
		~Method() {
			delete[] ru, en;
			ru = en = nullptr;
		}
	};
	
	/*адаптеры*/
	Adapter            * pAdapter;
	MemoryAdapter      * pMemoryAdapter;
	
	/*Локальное имя*/
	wchar_t * name;
	/*свойства, методы и классы*/
	long cnt_props;
	Prop ** Props;	
	long cnt_methods;
	Method ** Methods;
	/*заполнение свойств и методов*/
	void fill_name(const wchar_t * name);
	void fill_props(const Prop * Prors = nullptr, long cnt_props = 0);
	void fill_methods(const Method * Methods = nullptr, long cnt_methods = 0);
		
	virtual void addError(uint32_t wcode, const wchar_t* source, const wchar_t* descriptor, long code);

public:
	/*Деструктор*/
	virtual ~Base();
	/*Конструктор*/
	Base():cnt_props(0), Props(nullptr), cnt_methods(0), Methods(nullptr), pAdapter(nullptr), pMemoryAdapter(nullptr), name(nullptr) {}

	/*Инициализация и завершение*/
	virtual bool ADDIN_API Init(void*)                   override;
	virtual bool ADDIN_API setMemManager(void* mem)      override;
	virtual long ADDIN_API GetInfo()                     override;
	virtual void ADDIN_API Done()                        override;
	/*смена локализации*/
	virtual void ADDIN_API SetLocale(const WCHAR_T* loc) override;

	/*Расширение языка*/
	/*Регистрация расширения под конкретным именем*/
	virtual       bool     ADDIN_API RegisterExtensionAs(WCHAR_T**) override;

	virtual       long     ADDIN_API GetNProps() override  { return cnt_props; }
	virtual       long     ADDIN_API FindProp(const WCHAR_T* ex_name) override;
	virtual const WCHAR_T* ADDIN_API GetPropName(long num, long cur_locale) override;
	virtual       bool     ADDIN_API IsPropReadable(const long num) override;
	virtual       bool     ADDIN_API IsPropWritable(const long num) override;
	virtual       bool     ADDIN_API GetPropVal(const long num, tVariant* var) override { return false; } //заглушка на случай отсутствия свойств
	virtual       bool     ADDIN_API SetPropVal(const long num, tVariant* val) override { return false; } //заглушка на случай отсутствия свойств
	
	virtual       long     ADDIN_API GetNMethods() override  { return cnt_methods; }
	virtual       long     ADDIN_API FindMethod(const WCHAR_T* ex_name) override;
	virtual const WCHAR_T* ADDIN_API GetMethodName(const long num, const long cur_locale) override;
	virtual       long     ADDIN_API GetNParams(const long num) override;
	virtual       bool     ADDIN_API GetParamDefValue(const long num, const long lParamNum, tVariant *pvarParamDefValue) override { return false; }           //заглушка на случай отсутствия методов
	virtual       bool     ADDIN_API HasRetVal(const long num) override;
	virtual       bool     ADDIN_API CallAsProc(const long num, tVariant* paParams, const long lSizeArray);
	virtual       bool     ADDIN_API CallAsFunc(const long num, tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray);                           //заглушка на случай отсутствия методов
};


size_t wchar_to_WCHAR(WCHAR_T* &Dest, const wchar_t* Source, size_t len = 0);
size_t wchar_to_char(WCHAR_T * &Dest, const wchar_t* Source, size_t len = 0);
size_t WCHAR_to_wchar(wchar_t* &Dest, const WCHAR_T* Source, size_t len = 0);
size_t WCHAR_to_char(char * &Dest, const WCHAR_T* Source, size_t len = 0);
size_t WCHAR_len(const WCHAR_T* Source);
size_t wchar_len(const wchar_t* Source);

/* These functions should be implemented that component can be loaded and created. */
extern "C" long GetClassObject(const WCHAR_T*, Base** pIntf);
extern "C" long DestroyObject(Base** pIntf);
extern "C" const WCHAR_T* GetClassNames();

/*указатели на функции*/
typedef long(*GetClassObjectPtr)(const WCHAR_T* wsName, Base** pIntf);
typedef long(*DestroyObjectPtr)(Base** pIntf);
typedef const WCHAR_T* (*GetClassNamesPtr)();

#endif 
Показать
16. ture 580 15.03.16 18:57 Сейчас в теме
(12) TSSV, пример 1С, который я прокомментировал и вставил в архив, то же можно использовать. Однако пример 1С предназначен только для ознакомления и выяснения принципа взаимодействия. Ну я совсем все карты уже раскрыл.

18. ture 580 15.03.16 19:07 Сейчас в теме
(12) TSSV, выше я привел другую реализацию базового класса и вообще много переделал.
Идея простая:
1) пишем имя класса
/*объявляем имя класса доступное из 1С*/
        Base::fill_name(L"myClass");

2) указываем свойства
/*объявляем свойства доступные из 1С*/
        Base::Prop Props[] = {
            {L"Свойство_int"   , L"Prorp0", true, true},
            {L"Свойство_double", L"Prorp1", true, true},
            {L"Свойство_pchar" , L"Prorp2", true, true},
            {L"Свойство_bool"  , L"Prorp3", true, true},
            {L"Свойство_tm"    , L"Prorp4", true, true}
        };

русское, английское, можно читать, можно менять
3) доступ к свойствам
virtual bool ADDIN_API GetPropVal(const long num, tVariant* var) override {....
virtual bool ADDIN_API SetPropVal(const long num, tVariant * var) override {

4) указываем методы
/*объявляем методы доступные из 1С*/
        Base::Method Methods[] = {
            {L"Функция1", L"Func1", nullptr, nullptr, 1},
            {L"Функция2", L"Func2en", (void*)&std::bind(&myClass::Func2, this, _1, _2), nullptr, 2},
            {L"Процедура1", L"Proc1en", nullptr, (void*)&std::bind(&myClass::Proc1, this, _1, _2), 1, true}
        };        

русское, английское, указатель на функцию, указатель на процедуру, признак процедуры
(void*)&std::bind(&myClass::Proc1, this, _1, _2) здесь надо менять только название Proc1
(функцию еще не тестировал сам)
5) реализация процедур и функций
bool Proc1(tVariant* paParams, const long lSizeArray) {
....      
  return true; 
    }
    bool Func2(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray) {
....
        return true;
    }
20. TSSV 1058 15.03.16 22:45 Сейчас в теме
14. ture 580 15.03.16 18:53 Сейчас в теме
Это base.cpp
#include "base.h"
#include <wchar.h>
#include <iostream>
#include <string>



/*Реализация базового абстрактного класса*/
void Base::fill_name(const wchar_t * name) {
	/*копируем имя*/
	size_t len = wcslen(name) + 1;
	this->name = new wchar_t[len];
	memcpy(this->name, name, len*sizeof(wchar_t));
}
void Base::fill_props(const Prop * Props, long cnt_props) {
	/*заполним возможные свойства, если они есть*/
	if(cnt_props) {
		this->cnt_props = cnt_props;
		this->Props     = new Prop*[cnt_props];
		for(long i = 0; i < cnt_props; ++i)
			this->Props[i] = new Prop(Props[i]);
	}
}
void Base::fill_methods(const Method * Methods, long cnt_methods) {
	/*заполним возможные методы, если они есть*/
	if(cnt_methods) {
		this->cnt_methods = cnt_methods;
		this->Methods = new Method*[cnt_methods];
		for(long i = 0; i < cnt_methods; ++i)
			this->Methods[i] = new Method(Methods[i]);
	}
}

Base::~Base() {
	/*освобождаем массивы имен свойств*/
	for(long i = 0; i < cnt_props; ++i)
		delete Props[i];
	delete[] Props;
	Props = nullptr;
	cnt_props = 0;

	/*освобождаем массивы имен методов*/
	for(long i = 0; i < cnt_methods; ++i)
		delete Methods[i];
	delete[] Methods;
	Methods = nullptr;
	cnt_methods = 0;

	delete[] name;
}


bool Base::Init(void* pConnection) {
	pAdapter = (Adapter*)pConnection;
	return pAdapter != nullptr;
}
bool Base::setMemManager(void* mem) {
	pMemoryAdapter = (MemoryAdapter*)mem;
	return pMemoryAdapter != 0;
}
long Base::GetInfo() {
	/*Компонента должна сообщить свою версию*/
	return 2000;
}
void Base::Done() {}

void Base::SetLocale(const WCHAR_T* loc) {
	#ifndef __linux__
		_wsetlocale(LC_ALL, loc);
	#else
		//We convert in char* char_locale
		//also we establish locale
		//setlocale(LC_ALL, char_locale);
	#endif
}

bool Base::RegisterExtensionAs(WCHAR_T** ext_name) {
	if(pMemoryAdapter!=nullptr) {
		int len = wcslen(name) + 1;
		if(pMemoryAdapter->AllocMemory((void**)ext_name, len * sizeof(WCHAR_T)))
			wchar_to_WCHAR(*ext_name, name, len);
		return true;
	}else
		return false;
}

/*"Рефлексия" из 1С*/
long Base::FindProp(const WCHAR_T* ex_name) {
	long res = -1;
	wchar_t * temp = nullptr;
	WCHAR_to_wchar(temp, ex_name);
		
	for(long i = 0; res == -1 && i < cnt_props; ++i)
		if(!wcscmp(Props[i]->en, temp) || !wcscmp(Props[i]->ru, temp))
			res = i;
	
	delete[] temp;

	return res;
}
bool Base::IsPropReadable(const long num) {
	if(num < cnt_props)
		return Props[num]->r;
	else
		return false;
}
bool Base::IsPropWritable(const long num) {
	if(num < cnt_props)
		return Props[num]->w;
	else
		return false;
}
const WCHAR_T* Base::GetPropName(long num, long cur_locale) {
	if(num < cnt_props) {
		wchar_t * temp;
		if(cur_locale == 0)
			temp=Props[num]->en;
		else 
			temp = Props[num]->ru;		
		
		WCHAR_T * res_name = NULL;
		int len = wcslen(temp) + 1;
		
		if(pMemoryAdapter 
		   && temp
		   && pMemoryAdapter->AllocMemory((void**)&res_name, len*sizeof(WCHAR_T)))
				wchar_to_WCHAR(res_name, temp, len);
		
		return res_name;
	} else
		return nullptr;
}
long Base::FindMethod(const WCHAR_T* ex_name) {
	long res = -1;
	wchar_t * temp = nullptr;
	WCHAR_to_wchar(temp, ex_name);

	for(long i = 0; res == -1 && i < cnt_methods; ++i)
		if(!wcscmp(Methods[i]->en, temp) || !wcscmp(Methods[i]->ru, temp))
			res = i;

	delete[] temp;

	return res;
}
bool Base::HasRetVal(const long num) {
	if(num < cnt_methods)
		return Methods[num]->is_proc == false;
	else
		return false;
}
const WCHAR_T* Base::GetMethodName(const long num, const long cur_locale) {
	if(num < cnt_methods) {
		wchar_t * temp;
		if(cur_locale == 0)
			temp = Methods[num]->en;
		else
			temp = Methods[num]->ru;

		WCHAR_T * res_name = NULL;
		int len = wcslen(temp) + 1;

		if(pMemoryAdapter
		   && temp
		   && pMemoryAdapter->AllocMemory((void**)&res_name, len*sizeof(WCHAR_T)))
		   wchar_to_WCHAR(res_name, temp, len);

		return res_name;
	} else
		return nullptr;
}
long Base::GetNParams(const long num) {
	if(num < cnt_methods)
		return Methods[num]->cnt;
	else
		return 0;
}

void Base::addError(uint32_t wcode, const wchar_t* source, const wchar_t* descriptor, long code) {
	if(pAdapter) {
		WCHAR_T *err   = nullptr;
		WCHAR_T *descr = nullptr;

		wchar_to_WCHAR(err, source);
		wchar_to_WCHAR(descr, descriptor);

		pAdapter->AddError(wcode, err, descr, code);
		delete[] err, descr;
	}
}

bool Base::CallAsProc(const long num, tVariant* paParams, const long lSizeArray) { 
	if(num < cnt_methods && Methods[num]->proc != nullptr) {		
		return Methods[num]->proc(paParams, lSizeArray);		
	} else
		return false; 
}

bool Base::CallAsFunc(const long num, tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray) {
	if(num < cnt_methods && Methods[num]->func != nullptr) {
		return Methods[num]->func(pvarRetValue, paParams, lSizeArray);
	} else
		return false;
}
Показать
15. ture 580 15.03.16 18:54 Сейчас в теме
Это пример реализации class.hpp:
#include "base.h"
#include <ctime>

#ifndef CLASS_H
#define CLASS_H

class myClass: public Base {
private:
	int     Prop0 = -113; 
	double  Prop1 = 7.65;
	char  * Prop2 = nullptr;
	bool    Prop3 = true;
	tm      Prop4;
public:
	/*конструктор*/
	myClass() {
		/*объявляем имя класса доступное из 1С*/
		Base::fill_name(L"myClass");

		/*объявляем свойства доступные из 1С*/
		Base::Prop Props[] = {
			{L"Свойство_int"   , L"Prorp0", true, true},
		    {L"Свойство_double", L"Prorp1", true, true},
			{L"Свойство_pchar" , L"Prorp2", true, true},
			{L"Свойство_bool"  , L"Prorp3", true, true},
			{L"Свойство_tm"    , L"Prorp4", true, true}
		};
		Base::fill_props(Props, sizeof(Props) / sizeof(Base::Prop));

		/*объявляем методы доступные из 1С*/
		Base::Method Methods[] = {
			{L"Функция1", L"Func1", nullptr, nullptr, 1},
			{L"Функция2", L"Func2en", (void*)&std::bind(&myClass::Func2, this, _1, _2), nullptr, 2},
			{L"Процедура1", L"Proc1en", nullptr, (void*)&std::bind(&myClass::Proc1, this, _1, _2), 1, true}
		};		
		Base::fill_methods(Methods, sizeof(Methods) / sizeof(Base::Method));
		
		Prop2 = new char[100];
		std::strcpy(Prop2, "abc абС 123");

		time_t rawtime;
		time(&rawtime);
		Prop4 = *localtime(&rawtime);		
	}
	~myClass() { 
		delete[] Prop2; 		
	}
	
	/*Получение свойства*/
	virtual bool ADDIN_API GetPropVal(const long num, tVariant* var) override {
		switch(num) {
			case 0: //Свойство_int
				TV_VT(var) = VTYPE_I4; //выставляем тип
				TV_I4(var) = Prop0;    //выставляем значение
				break;
			case 1: //Свойство_double
				TV_VT(var) = VTYPE_R8;  //выставляем тип
				TV_R8(var) = Prop1;     //выставляем значение
				break;
			case 2: //Свойство_pchar
				TV_VT(var) = VTYPE_PSTR;  //выставляем тип
				var->pstrVal = Prop2;     //сразу указатель на строку
				var->strLen  = std::strlen(Prop2);
				break;
			case 3: //Свойство_bool
				TV_VT(var) = VTYPE_BOOL; //выставляем тип
				TV_BOOL(var) = Prop3;    //выставляем значение
				break;
			case 4: //Свойство_tm
				TV_VT(var) = VTYPE_TM; //выставляем тип
				var->tmVal = Prop4;    //выставляем значение
				break;
			default:
				return false;
		}
		return true;
	}
	/*Установка свойства*/
	virtual bool ADDIN_API SetPropVal(const long num, tVariant * var) override {
		switch(num) {
			case 0:
				if(TV_VT(var) != VTYPE_I4)
					return false;
				Prop0 = TV_I4(var);
				break;
			case 1:
				if(TV_VT(var) != VTYPE_R8)
					return false;
				Prop1 = TV_R8(var);
				break;
			case 2:
				if(TV_VT(var) == VTYPE_PSTR) { 
					delete[] Prop2;
					size_t len = std::strlen(var->pstrVal);
					Prop2 = new char[len + 1];
					std::strncpy(Prop2, var->pstrVal, len + 1);
					break;
				} else if(TV_VT(var) == VTYPE_PWSTR) {
					delete[] Prop2;
					WCHAR_to_char(Prop2, var->pwstrVal);
					break;
				} else
					return false;
			case 3:
				if(TV_VT(var) != VTYPE_BOOL)
					return false;
				Prop3 = TV_BOOL(var);
				break;
			case 4:
				if(TV_VT(var) != VTYPE_TM)
					return false;
				Prop4 = var->tmVal;
				break;
			default:
				return false;
		}
		return true;
	}
	/*Методы*/
	bool Proc1(tVariant* paParams, const long lSizeArray) {
		return true; 
	}
	bool Func2(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray) {
		return true;
	}
};

#endif
Показать
17. ture 580 15.03.16 18:58 Сейчас в теме
(15) ture, этот метод
{L"Функция1", L"Func1", nullptr, nullptr, 1},
не реализован.
19. ture 580 15.03.16 19:09 Сейчас в теме
Я еще работаю над реализацией базового класса.
23. MherArsh 24 16.03.16 09:22 Сейчас в теме
Привет всем!

В принципе ничего сложного, я тоже когда то делал так, писал компоненту для работы с картинками.

Могу дать один совет начинающим, используйте C++Builder (Embarcadero) вместо Visual C++, там реально дохрена всяких классов под любое требование, начиная с простого до веб сервисов например .
24. Ivon 659 16.03.16 11:55 Сейчас в теме
Вроде бы все красиво и понятно, но в заголовке нужно добавить "для С++". Например я С++ не знаю, но знаю C#. При этом должен отметить, что подобные внешние компоненты, которые не интегрируются в интерфейс 1С, не так сложно начать писать и на C#. Мне удалось собрать по крупицам информацию, достаточную для написания интерфейсных ВК и даже написать такую ВК для собственных нужд (чтение изображения из базы MSSQL и отображение этого изображения в самой компоненте, так как поле картинки в 1С при смене картинки в поле не освобождает память, в итоге клиент можно крашануть просто меняя в поле 2 картинки одну на другую 100500 раз), но процесс очень сложно назвать легким для понимания. Поэтому я отслеживаю подобные статьи в надежде на поиск нормальной инструкции. Сам инструкцию пока написать не могу, так как некоторые манипуляции делаются без понимания, зачем они нужны, но со знанием, что если этого не сделать, то ВК не заработает.
invertercant; +1 Ответить
25. skyadmin 101 17.03.16 13:04 Сейчас в теме
(24) Ivon, аналогично сдлал, только на VB.NET.
Если бы был пример на C#, то можно было бы через Convert .NET преобразовать C# в VB.NET, попробовать.
26. ture 580 17.03.16 13:44 Сейчас в теме
(25) skyadmin, пример на c#?
В прошлом году возился с шарпом. Все компоненты через COM требуют регистрации. С админами не договориться без ружья на медведя... Чуть что серьезное и на шарпе нету, надо собирать dll из исходников на с/с++/java.... а то и вообще выковыривать из опенсорс под линукс. Короче говоря, шарп решил бросить.
27. talych 17 17.03.16 16:12 Сейчас в теме
Есть внешняя компонента, написанная для 1С 8.1 В ней использовал CDialogEx
Можно ли использовать их в Native API? Клиенты работают только на винде. Пытаюсь выполнить код, вылетает в assert
		if(!m_pDlg)
			{
				m_pDlg = new CMainDlg();
				m_pDlg->Create(IDD_DIALOG2);
			}
29. ture 580 22.03.16 18:27 Сейчас в теме
Чуток промазал в исходниках. Правильней так.

size_t wchar_to_char(char * &Dest, const wchar_t* Source, size_t len) {
	/*if(len == 0) {//если размер задан, то и место уже зарезервировано
		len = wchar_len(Source) +1;
		Dest = new char[len];
	}
	wcstombs(Dest, Source, len);
	Dest[len - 1] = '\0';*/
	
	if(len == 0) {
		len = WideCharToMultiByte(
			1251,   // Code page
			0,      // Default replacement of illegal chars
			Source, // Multibyte characters string
			-1,     // Number of unicode chars is not known
			NULL,   // No buffer yet, allocate it later
			0,      // No buffer
			NULL,   // Use system default
			NULL    // We are not interested whether the default char was used
			);
		if(len == 0)
			return 0;
		else
			Dest = new char[len]; 
	}

	len = WideCharToMultiByte(
		1251,    // Code page
		0,       // Default replacement of illegal chars
		Source,  // Multibyte characters string
		-1,      // Number of unicode chars is not known
		Dest,    // Output buffer
		len,     // buffer size
		NULL,    // Use system default
		NULL     // We are not interested whether the default char was used
		);

	if(len == 0) {
		delete[] Dest;
		return 0;
	}

	return len;
}
Показать
30. so-quest 134 27.03.16 23:48 Сейчас в теме
Примерно представляя сколько труда надо вложить в статью, говорю - спасибо. Написано немного сумбурно, но читаемо. Единственное что хотел бы добавить - если не стоит цели заработать старманей, то стоит подумать об использовании github или ему подобных серверов.

31. ture 580 29.03.16 15:40 Сейчас в теме
(30) so-quest, нет цели зарабатывать монетки. Я, как и все, складирую полезные вещи с описанием. В какой-то момент статья была в тренде... пришлось поподробней и побольше написать.
32. ture 580 30.03.16 14:57 Сейчас в теме
На сервачке:
	Объект_=РеквизитФормыВЗначение("Объект");			
			адрес = ПоместитьВоВременноеХранилище(Объект_.ПолучитьМакет("SuperI"));
			res=ПодключитьВнешнююКомпоненту(адрес,"VK",ТипВнешнейКомпоненты.Native);			
			obj = Новый("AddIn.VK.myClass");
33. ture 580 30.03.16 18:47 Сейчас в теме
На клиенте:
&НаСервере
Функция GetInf()
	Перем стРезультат;
	
	oSQL=Объект.Код;
	бРезультат=ВыполнитьSQL(oSQL,"select 1 as [q]");
	Если бРезультат тогда 		
		Объект_ = РеквизитФормыВЗначение("Объект");
		стРезультат=Новый Структура("Адрес,Сервер,База,Пользователь,Пароль",
									ПоместитьВоВременноеХранилище(Объект_.ПолучитьМакет("Макет_v2"),Новый УникальныйИдентификатор),
		                            oSQL.Server,
									oSQL.Base,									
									"***","***");		
	КонецЕсли;
	
	Возврат стРезультат;
КонецФункции	

&НаКлиенте
Процедура xmlНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
	Перем Criterion;
	
	СтандартнаяОбработка=Ложь;
	стРезультат=GetInf();
	Если стРезультат<>Неопределено тогда 
		Попытка 
			res=ПодключитьВнешнююКомпоненту(стРезультат.Адрес, "VK", ТипВнешнейКомпоненты.Native);					
			Criterion = Новый("AddIn.VK.Criterion");			
		Исключение
			УстановитьВнешнююКомпоненту(стРезультат.Адрес);
			res=ПодключитьВнешнююКомпоненту(стРезультат.Адрес, "VK", ТипВнешнейКомпоненты.Native);					
			Criterion = Новый("AddIn.VK.Criterion");		
		КонецПопытки;
		УдалитьИзВременногоХранилища(стРезультат.Адрес);
		
		Criterion.Сервер=стРезультат.Сервер;
		Criterion.База  =стРезультат.База;
		Criterion.КритерийОтбора ="";
		Criterion.ПользовательSQL=стРезультат.Пользователь;
		Criterion.ПарольSQL      =стРезультат.Пароль;
		Объект.xml=Criterion.ПолучитьXMLфайл();
	КонецЕсли;
КонецПроцедуры
Показать


В макет складываем манифест и все прописанные в нем dll (достаточно под 32 и 64 бита на ведре)
34. IgorLee 18.06.16 09:18 Сейчас в теме
Всем привет !

(1С8.3.5.1625)

Кто либо сталкивался с проблемой, что компонента "сама выгружается" от 1С или 1С её выгружает сама без какой либо причины ?

Т.е. - загружаю компоненту, к примеру в форме дока (сохраняется в переменной формы дока), далее проходит время (минут 15 и более бывает) и компонента "выгружается" от 1С8.

Примечание: в компоненту добавил логирование, соотв. из логов делаю вывод
35. IgorLee 18.06.16 14:59 Сейчас в теме
(34) IgorLee,

В общем вроде разобрался.

Дело вот в чем - 1С8 сама выгружает компоненту ровно через 20 минут, проверял кучу раз (расхождение не более 15 сек. между "опытами") !

Но что я раскопал...
Оказывается если у "IAddInDefBaseEx" запросить интерфейс "IMsgBox" и/или "IPlatformInfo" через метод "GetInterface(...)" - и хранить значение этого интерфейса, к примеру, в локальной переменной класса компоненты - то 1С не выгружает Вашу компоненту !

Оч. странно вышло :(
36. ture 580 20.06.16 11:51 Сейчас в теме
(35) IgorLee, меня тут в sap окунули с головой. И как-то склоняться я к мысли стал, что 1С не игрок на мировом рынке. Больше того 1С не игрок и на своем рынке после того свинства с переходом с 1С7.7 к 1С8. Я имею ввиду то, что пришлось не просто код программ целиком переписывать, а даже самих программистов переучивать. Теперь старожилы 1С не сильно вникают в тонкости и детали платформы, потому что знают что однажды всё снова изменится и заплатят они дорого за своё "тайное" и выстраданное знание, не желая от него отказаться. В итоге в 1С остаются только лошки, которые и программистами называют себя с натяжкой и знают, что доход их складывается от знания бредовой реализации типовых конфигураций, а не программирования и знания внутреннего языка. Такого в SAP не было сколько мне известно. Вот такие вот тонкости.
Оставьте свое сообщение

См. также

Внешняя компонента: Android tools Промо

Мобильная разработка Разработка внешних компонент v8 v8::Mobile Абонемент ($m)

Несколько дополнительных функций для мобильного приложения\клиента под Android. Размер архива внешних компонент под архитектуры ARM и x86 - 230KB.

1 стартмани

12.01.2021    2085    5    KAV2    8    

Описание работы внешней компоненты 1С SBRFCOM.DLL для обслуживания банковских карт

Эквайринг Разработка внешних компонент v8 1cv8.cf Россия Абонемент ($m)

Описание работы внешней компоненты 1С SBRFCOM.DLL для обслуживания банковских карт, приведены методы и функции по работе с данной компонентой.

1 стартмани

09.03.2021    1369    2    artemua    7    

Использование встроенного сканера ТСД на Android в мобильном клиенте и мобильном приложении (драйвер сканера Android для 1С)

Разработка внешних компонент Мобильная разработка v8 Абонемент ($m)

Используя данный драйвер, можно без единой строки кода, просто установив на ТСД мобильный клиент 1С, сразу начать подбирать товары в документах вашей учётной системы. А, адаптировав нужные формы под небольшой размер экрана ТСД, можно просто создать полноценное рабочее место для выполнения операций с помощью ТСД, не прибегая к стороннему софту. Если же на складе плохая связь (или её нет вовсе), то можно использовать возможности мобильного клиента в автономном режиме (потребуется доработка вашей конфигурации). Драйвер также можно использовать и для Android приложения на мобильной платформе. В результате чего можно обойтись без ненужных полей ввода и клавиатуры «на пол-экрана».

3 стартмани

09.10.2020    11264    100    ltfriend    92    

Отрубаем зависшие на сервере процессы

Разработка внешних компонент v8 1cv8.cf Абонемент ($m)

Вы любите COM объекты? Я их просто обожаю! Практически все, чего не может 1С, можно доделать ими. Но есть у них небольшой косячок: иногда они зависают и висят, пока не отрубишь их через диспетчер задач или до перезагрузки, жрут память и в конце концов перестают запускаться. Что делать? Рубить!

1 стартмани

28.07.2020    3418    1    zarankony    3    

Внешняя компонента для работы по Web-socket протоколу x32 x64 Промо

Разработка внешних компонент WEB v8 Абонемент ($m)

Кто когда-нибудь сталкивался с обменом данными по Web-Socket (wss) протоколу из 1С, тому известно, что в платформе отсутствуют данные механизмы (не путать с HTTP запросами и WebServices). Предлагается использовать внешнюю компоненту, написанную по технологии NativeAPI, для подключения и обмена с серверами из 1С-Предприятия, работающими по протоколу Web-Socket.

1 стартмани

30.03.2018    31085    41    Ditron    93    

Диагностика контекста выполнения (внешняя компонента)

Разработка внешних компонент v8 1cv8.cf Абонемент ($m)

Небольшая экспериментальная внешняя компонента для получения дополнительной информации о контексте выполнения.

1 стартмани

24.07.2020    6732    2    YPermitin    14    

Универсальная обертка для использования NATIVE компонент на платформе 1С 7.7, 8.0 и 8.1

Разработка внешних компонент v8 Абонемент ($m)

Используете 1С 7.7, 8.0 или 8.1 и вас раздражает, что под вашу 1С уже не выпускаются современные компоненты. А хотелось бы?

1 стартмани

07.07.2020    4942    7    karpik666    5    

Нано HTTP сервер - внешняя компонента для мобильного приложения 1C, на Android

Разработка внешних компонент Мобильная разработка v8 v8::Mobile 1cv8.cf Абонемент ($m)

Нано HTTP сервер на терминале сбора данных "ATOL Smart.Lite android 7.0". Работает только с GET и POST запросами. Аутентификация BASE64. Не поддерживает HTTPS и не передает файлы. В прикрепленном архиве исходники на компоненту (С++ и java для Android Studio 3.6.2), ЦФ - мобильного приложения и тестовая обработка.

1 стартмани

22.06.2020    4811    10    SanyMaga    19    

TextRadar - нечеткий поиск в тексте Промо

Разработка внешних компонент Поиск данных v8 1cv8.cf Абонемент ($m)

В отличие от нечеткого сравнения строк, когда обе сравниваемых строки равнозначны, в задаче нечеткого поиска выделяются строка поиска и строка данных, а вычислить необходимо не степень похожести двух строк, а степень присутствия строки поиска в строке данных. Нормированный коэффициент, находящийся между 0 и 1 позволяет отсечь заведомо низкие результаты, организовать поиск по синонимам и т.д. Наглядное отображение результатов в кратком и детальном виде поможет быстро найти интересующий фрагмент.

1 стартмани

19.09.2018    20686    30    TSSV    19    

Получение фото с веб-камеры

Разработка внешних компонент v8 Абонемент ($m)

Получение фото с веб-камеры без ActiveX. Внешняя компонента по технологии Native API.

1 стартмани

25.03.2020    8275    73    berezdetsky    41    

Пауза без загрузки процессора. Внешняя компонента Native API на C++

Разработка внешних компонент v8 Абонемент ($m)

Внешняя компонента Native API на C++ для Win32 и Win64 позволяет установить паузу на заданное количество секунд без загрузки процессора.

2 стартмани

21.03.2020    3777    4    DNN13    26    

Быстрая печать этикеток (ZPL, EPL, TSPL, EZPL, GEPL, TSPL-EZ)

Разработка внешних компонент v8 v8::УФ 1cv8.cf Абонемент ($m)

Качественная и быстрая печать на внутреннем языке принтеров этикеток.

4 стартмани

02.02.2020    10031    44    Johny_v    13    

Использование сборок .NET в 1С 7. и 8.x. Создание внешних Компонент. Промо

Разработка внешних компонент v7.7 v8 1cv8.cf 1cv7.md Абонемент ($m)

Данная разработка создана для использования сборок .Net в 1С через преобразование объектов и классов в COM-объекты, которые можно использовать в 1С. Достигается это путем создания класса, реализующего методы интерфейса IReflect public class AutoWrap: IReflect.

1 стартмани

28.11.2013    88064    284    Serginio    74    

Сканирование по TWAIN в 1С (обычные и управляемые формы)

Разработка внешних компонент v8 v8::УФ 1cv8.cf Абонемент ($m)

Обработка показывает пример, как можно в 1С проводить сканирование с помощью компоненты TWAIN.

3 стартмани

03.01.2020    7524    29    Denr83    0    

Вставка картинки из буфера обмена (на выбор: JavaScript / внешняя компонента / штатно)

Разработка внешних компонент v8 Абонемент ($m)

Вставка картинки из буфера обмена с помощью JavaScript в поле HTML в web-клиенте, с помощью внешней компоненты в тонком/толстом клиенте и путем преобразования данных картинки формата Base64 из поля HTML в любом клиенте, начиная с платформы 8.3.16. Механизм протестирован на платформах 8.2 и 8.3 Для запуска опубликованной конфигурации требуется платформа релиза не ниже 8.3.14.

1 стартмани

05.12.2019    6298    7    Andreyyy    10    

Клиент событий в «бесконечном» HTTP-соединении для 1С: Предприятие 8

Разработка внешних компонент v8 1cv8.cf Абонемент ($m)

Native Компонента в отдельном потоке обрабатывает пакеты событий, в "бесконечном" http соединении и передаёт данные в очередь внешних событий.

1 стартмани

02.12.2019    5933    2    starovton    11    

Tool1CD Beta в деле Промо

Разработка внешних компонент v8 Абонемент ($m)

Пс, парень! Не хочешь немного сырых байтов?

1 стартмани

09.05.2018    28732    31    baton_pk    26    

Управление окнами и мониторами в 1С

Сервисные утилиты Разработка внешних компонент v8 1cv8.cf 1С:Франчайзи, автоматизация бизнеса Абонемент ($m)

Управление размерами, активностью и положением окон из 1С с возможностью вывода окон на второй монитор и запретом изменения окна.

1 стартмани

28.10.2019    11000    12    Grigoriy251    7    

Маленькая и скромная мобильная внешняя компонента

Разработка внешних компонент v8 Абонемент ($m)

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

1 стартмани

21.10.2019    11454    8    ripreal1    34    

Native внешняя компонента для оповещения по UDP или TCP

Разработка внешних компонент v8 Абонемент ($m)

Native внешняя компонента для оповещения по UDP или TCP, которая реализует возможность в 1С передавать сообщения с сервера на клиента. Исходный код компоненты также представлен.

1 стартмани

06.10.2019    12606    28    vdv2701    31    

NativeDraw: Компонента рисования для 1С [V2.6.2] Промо

Разработка внешних компонент Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Рисуйте в формах 1С, также предлагается небольшое количество нерисовальных функций

1 стартмани

13.07.2015    50478    466    ПерваяСистема    147    

Внешняя компонента Sundries: несколько полезных системных функций

Разработка внешних компонент v8 Абонемент ($m)

Звук, пауза, буфер обмена, раскладки клавиатуры и т.д.

4 стартмани

30.08.2019    7548    9    sivin-alexey    15    

Native внешняя компонента для передачи/получения по UDP (теперь с Base64)

Разработка внешних компонент v8 УТ10 Россия Абонемент ($m)

Внешняя компонента Native-API для организации передачи с использованием UDP.

1 стартмани

29.07.2019    5692    11    axae    2    

Внешняя компонента для работы с драйвером "Атол v.10". 1С:8.3

Разработка внешних компонент Кассовые операции Кассовые операции v8 Абонемент ($m)

Внешняя компонента, для работы с драйвером «Атол v.10», посредством JSON-заданий.

1 стартмани

16.07.2019    13732    30    gortrex    5    

Компоненты распознавания и печати штрих-кодов Промо

Разработка внешних компонент Сканер штрих-кода v7.7 v8 1cv8.cf 1cv7.md Абонемент ($m)

Комплект программного обеспечения для реализации функций оптического распознавания штрих-кодов различных систем при помощи обычной web-камеры, а также их отображения в печатных формах. Программы могут работать в составе конфигураций, созданных на базе платформ «1С-Предприятие» версий 7.7, 8.2, 8.3. Компонент чтения кодов реализован в виде внешней компоненты 1С с COM-интерфейсом. Компонент отображения создан по стандартной технологии ActiveX для Windows, и может быть встроен в любое приложение, поддерживающее встраивание ActiveX элементов управления, например в документ Word или Excel, или форму VBA. P.S. Добавлена новая версия программы распознавания. Новые функции: обработка видео в реальном режиме (а не по таймеру, как раньше), добавлена возможность распознавания штрих-кодов из графических файлов JPEG, PNG, GIF, BMP, а также передавать для распознавания картинки из 1С, теперь можно получить в 1С захваченное с камеры или файла изображение, как с выделением мест, содержащих коды, так и без, а также отдельные фрагменты изображений, содержащие код. Добавлены новые свойства и методы для программирования. Обновлена документация.

10 стартмани

10.07.2015    73324    88    igorberezhnov    101    

Менеджер буфера обмена. Нативная внешняя компонента win 32/64

Разработка внешних компонент v8 1cv8.cf Абонемент ($m)

Добавляет возможности получения информации из почтовых вложений или файлов с других рабочих столов (RDP) с помощью операций копирования/вставки. Может «прослушивать»: любые изменения буфера обмена; нажатие клавиш соответствующих вставке (paste); нажатие клавиш копирования (copy); drop операции. Это новая реализация аналогичной компоненты https://infostart.ru/public/379695/, но теперь не C#, а С++ нативно для x32 / x64. (см. http://youtu.be/-PaWWFfbYo4)

1 стартмани

26.06.2019    8138    26    Bww    23    

Обработка вывода на печать QR-кода и штрихкодов в различных форматах (одномерные и двумерные)

Разработка внешних компонент Ценники v8 v8::УФ 1cv8.cf Россия Абонемент ($m)

Обработка предназначена для вывода на печать QR-кода и штрихкодов в различных форматах без установки дополнительных ActiveX компонент. Тестировалась на чистой базе платформы 1С:Предприятие 8.3 (8.3.14.1630), а так же в конфигурациях Бухгалтерия предприятия КОРП, редакция (3.0.69.35) и на Бухгалтерия предприятия (3.0.70.30)

2 стартмани

22.05.2019    12917    47    MGemini    3    

DLL для подключения к Asterisk (32/64 клиенты)

Разработка внешних компонент Телефония, SIP v8 1cv8.cf Абонемент ($m)

Подключение к Астериску и получение событий "Newchannel","BridgeEnter","Hangup" через ОбработкаВнешнегоСобытия.

1 стартмани

19.03.2019    9621    13    xxxAndricxxx    14    

Полезные приемы при работе с Excel из 1С (Версия 3.1) Промо

Практика программирования Разработка внешних компонент Загрузка и выгрузка в Excel v8 1cv8.cf Абонемент ($m)

Программисту 1С часто приходится работать с таблицами Excel из 1С. Я постарался собрать небольшой FAQ и набор функций для работы с файлами Excel. Надеюсь, кому-то будет полезна данная статья.

1 стартмани

22.09.2015    227443    478    Zerocl    77    

DLL для обмена между 1С (и не только) через UDP порты (32/64 клиенты)

Разработка внешних компонент v8 1cv8.cf Россия Абонемент ($m)

Библиотеки для создания функционала для прослушивания портов из 1С и отправки сообщений на удаленный udp порт.

1 стартмани

28.02.2019    8736    10    xxxAndricxxx    3    

Эмулятор ККМ по стандарту ФФД 1.1

Разработка внешних компонент Кассовые операции ККМ Кассовые операции v8 Розница УТ11 Россия Абонемент ($m)

Эмулятор драйвера ККМ по стандарту ФФД 1.1 предназначен для использования всех возможностей программы, при отсутствии физической кассы. Подойдет как программистам при разработке интерфейса РМК, например, так и пользователям для тестирования возможностей программы.

1 стартмани

30.12.2018    26169    149    Matveymc    30    

WebSocket Клиент / Сервер. Внешний компонент

Разработка внешних компонент v8 1cv8.cf Абонемент ($m)

Реализация протокола WebSocket. Клиентская часть для взаимодействия с внешними сервисами. Серверная часть для организации собственного сервера, принимающего клиентские соединения в многопоточном режиме. Возможно взаимодействие RabbitMQ Slack Asterisk и другие

1 стартмани

16.11.2018    19922    87    nomadon    66    

Снимок экрана для 1С Промо

Универсальные обработки Разработка внешних компонент v8 1cv8.cf Россия Абонемент ($m)

Довольно часто люди сталкиваются с необходимостью сделать снимок экрана. Если вы или ваши сотрудники основную часть времени проводят в 1С и у вас есть необходимость прикреплять графические файлы, то эта компонента для вас.

1 стартмани

08.02.2016    30252    34    linkforget    11    

Внешняя компонента для выполнения регулярных выражений

Разработка внешних компонент v8 Абонемент ($m)

Внешняя Native API компонента для выполнения регулярных выражений на платформе 1С:Предприятие 8. Написана на C++. Используется движок boost::regex (v 1.69, v 1.68 - для Android). Версия синтаксиса Perl Compatible Regular Expressions.

1 стартмани

12.11.2018    14925    36    KAV2    68    

Native компонента для 8.3, реализующая метод sleep()

Разработка внешних компонент v8 Россия Абонемент ($m)

Внешняя Native 64-битная компонента для 1C 8.3, которая реализует метод sleep() - паузу выполнения кода. Пауза для большой устойчивости сделана платформозависимой и требует WinAPI. Ид компоненты - AddIn.AddInNativeSleep.NativeSleep.

1 стартмани

16.10.2018    9325    3    ripreal1    9    

001. Криптография и цифровая подпись RSA-sha256 на платформе 1С

Разработка внешних компонент v8 1cv8.cf Абонемент ($m)

Внешняя компонента, исходники, обработка для 1С.

5 стартмани

04.09.2018    18051    38    Nikola23    69    

Native API компонента для использования установленного в системе интерпретатора Python Промо

Разработка внешних компонент v8 1cv8.cf Абонемент ($m)

Компонента позволяет подключать к платформе 1С python-модули, оформленные в стиле внешней компоненты. Кроме этого, она позволяет запускать небольшие фрагменты python-кода прямо из модулей 1С. На данный момент поддерживаются платформы 8.2 — 8.3 x86 Windows.

1 стартмани

14.05.2013    42336    84    Принт    31    

Класс-обработка “Работа с картами Яндекс”

Разработка внешних компонент WEB v8 Абонемент ($m)

Как показать точку или маршрут на карте Яндекс. Как получить координаты по строке адреса (геокодирование).

1 стартмани

01.08.2018    29889    224    RSConsulting    17    

Распознавание лиц (off-line). Демонстрационная база.

Разработка внешних компонент v8 Абонемент ($m)

Распознавание лиц входит в нашу жизнь стремительными темпами, бизнес стремится за событиями. В публикации находится описание и пример использования нейросетей для распознавания лиц.

1 стартмани

17.07.2018    18314    75    nomadon    45    

QR-code полная версия (без шрифта и внешней компоненты для 8.2, 8.3 и любого типа клиента)

Разработка внешних компонент Сканер штрих-кода v8 1cv8.cf Абонемент ($m)

Предназначена для создания QR-code с указанием процента восстановления потерянных данных. Строка кодирования может содержать все печатаемые символы, в том числе и кириллические. Для работы не требуется внешняя компонента или шрифт.

2 стартмани

10.07.2018    13904    16    bobank    6    

Распознаем штрих-коды QR, EAN-13, Code 128 с помошью 1С и веб камеры Промо

Разработка внешних компонент v8 1cv8.cf Россия Абонемент ($m)

Внешняя компонента, поможет распознать штрих-код, используя обычную веб камеру. Умеет работать с UPC-A, UPC-E, EAN-8, EAN-13, Code 39, Code 128, QR Code, Interleaved 2 of 5, Codabar, RSS-14, Data Matrix, PDF 417, Aztec, MaxiCode.

1 стартмани

31.10.2012    80885    244    shakmaev    84    

Внешняя компонента для ping'а

Разработка внешних компонент v8 1cv8.cf Абонемент ($m)

Внешняя компонента для выполнения ping'а из 1С:Предприятия 8.

1 стартмани

04.07.2018    12461    5    frkbvfnjh    24    

JVM Native API плагин - для запуска в 1С плагинов написанных на Java

Разработка внешних компонент v8 Абонемент ($m)

Запускаем виртуальную машину Java в 1С. Собрана внешняя компонента которая позволяет запускать виртуальную машину java в среде 1С. Позволяет как передавать параметры в java - так и получать уведомление через externalevent. Предпосылкой создания являлся тот факт, что есть много готового функционала которого не хватает в 1С. Язык сpp - довольно сложен для быстрой разработки, и теперь возможно использовать готовые сборки java классов (так называемые jar-файлы) для использования в 1С.

1 стартмани

20.06.2018    14914    36    minimajack    73    

Вызов методов 1С из внешней компоненты, выполненной по технологии COM на C++

Разработка внешних компонент v8 Абонемент ($m)

Пример работы с объектами и методами 1С из внешней компоненты, разработанной по технологии COM на С++.

1 стартмани

04.06.2018    10062    6    le_    1    

Удаленное управление через Skype Промо

Разработка внешних компонент Администрирование данных 1С v8 1cv8.cf Абонемент ($m)

Удаленное управление 1С через Skype. Со стороны клиента для работы нужен только Skype. Со стороны сервера любой компьютер с 1С.

1 стартмани

09.02.2014    46375    68    moolex    29    

Внешняя компонента Native для создания штрих кода (GS1 DataBar Expanded, GS1 DataBar Expanded Stacked и другие)

Разработка внешних компонент v8 1cv8.cf Абонемент ($m)

В связи с внедрением ГИС Меркурий потребовалось внешняя компонента, которая создает штрихкод и отдает 1С. ВК создана на основе библиотеки zint www.sourceforge.net/projects/zint.

1 стартмани

27.04.2018    21059    229    artmaks1988    93    

Работа с любыми сканерами документов в 1С c помощью внешней компоненты от vintasoft.com

Разработка внешних компонент v8 v8::УФ 1cv8.cf Абонемент ($m)

Универсальная обработка для сканирования изображений на любых сканерах (поточных, планшетных) средствами ActiveX от компании Vintasoft.

1 стартмани

29.03.2018    9706    4    Dach    0    

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

Разработка внешних компонент v8 Россия Абонемент ($m)

Не знаю, пригодится кому или нет, писалось для себя, т.к  возникла необходимость печатать на принтере этикеток sscc напрямую с ТСД  через web - сервис. Как известно, веб сервис в 1С работает только в серверном контексте и, к сожалению, разработчики платформы пока не позаботились о возможности вызывать метод  при таких условиях. 

1 стартмани

13.03.2018    12099    34    evgeny43    13    

Внешняя компонента - Запись и воспроизведение .wav файлов. Обработка-иллюстратор. Промо

Разработка внешних компонент v8 1cv8.cf Абонемент ($m)

Обработка иллюстрирует использование внешней компоненты MMLibrary для записи и воспроизведения звуковых wav файлов. Компонента разработана по технологии Native.

1 стартмани

01.03.2014    19625    33    vozhd    7