Для использования .NET сборок в 1С обычно приходится их регистрировать как com-объекты, что не всегда удобно. Предлагаемая компонента выполнена по технологии Native API и дает возможность использовать такие компоненты без установки и без регистрации в реестре windows.
(1) OldthiefXXX, да, требований никаких нет, есть только ограничения(описаны в публикации), главное - это ограничение типов, например объект из компоненты вернуть нельзя(ограничение технологии Native API).
(1) Спасибо большое за обработку.
Удалось создать тестовый проект со сборкой dll на IDE SharpDevelop c .Net 4. Взял текст вашего класса, создал x64 dll, загрузил в макет обработки 1с.
Запустил в 1с, dll запустилась, отработала.
Пара моментов на данный момент не работают:
1. Запуск dll в контексте клиента не отрабатывает, работает только контекст сервера.
С аналогичной проблемой уже сталкивались люди, см. ввыше комментарии.
2. Запуск обработки с управляемой формой возможен либо в управляемом режиме 1с, либо в неуправляемом с созданием неуправляемой формы и переносом функционала в нее.
Это проблема платформы.
Официально, это новая фишка 1с платформы.
На самом деле - баг, который с 2014 года не исправляют.
Спасибо за компоненту, но при использовании появилось несколько вопросов.
Объясните пожалуйста более подробно, каким образом мы загружаем dll"ку на C#. Из кода демки внешней обработки понятно, что zip архив с манифестом и dll'ка C++ NETLoader_x32.dll загружаются в макет формы. Дальше, при инициализации компоненты в самой базе они загружаются.
Не понятно каким образом Test.dll с кодом C# попадает в обработку.
В коде формы есть строки:
КаталогКомпонент = КаталогВременныхФайлов() + Новый УникальныйИдентификатор;
(7) Не очень понял, о чем речь. Если я не ошибаюсь, у Elisy компонента представляет собой полноценный com-объект, соответственно можно обмениваться кроме простых типов также объектами. А технология NativeAPI позволяет передавать только простые типы (число, строка, булево, дата, массив байтов).
Если есть возможность использовать com-объект, то наверное стоит использовать его, т.к. он удобнее в использовании. NativeAPI удобнее только в распространении, т.к. не надо ничего регистрировать. Собственно для этого я и сделал её, потому что бывает, что нет возможности развернуть нужное ПО на компьютерах клиента.
Я про то, что объект можно обернуть нетовский класс объект в наследнике IComponentBase.
То есть по аналогии с моей компонентой
public static object ОбернутьОбъект(object obj)
{
if (obj != null)
{
//switch (obj.GetType().ToString())
//{
// case "System.String":
// case "System.DateTime":
// case "System.Boolean":
// case "System.Byte":
// case "System.Char":
// case "System.Decimal":
// case "System.Double":
// case "System.Single": // Float
// case "System.Int32":
// case "System.Int64": // Long
// case "System.SByte":
// case "System.Int16":// Short
// case "System.UInt32":
// case "System.UInt64":
// case "System.UInt16":
// break; // These Types do not get wrapped
// default:
// obj = new AutoWrap(obj); // Wrap Type
// break;
//}
// Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double и Single.
Type Тип = obj.GetType();
if (Тип==typeof(System.IntPtr) || Тип==typeof(System.UIntPtr))
return new AutoWrap(obj);
if (ЭтоСемерка)
{
if (Тип == typeof(System.Decimal)) return ((Decimal)obj).ToString(CultureInfo.InvariantCulture);
if (Тип.IsPrimitive)
{
if ((Тип == typeof(System.Int64) || Тип == typeof(System.UInt32) || Тип == typeof(System.UInt64) || Тип == typeof(System.UInt16) || Тип == typeof(System.SByte)))
obj = Convert.ChangeType(obj, typeof(string), CultureInfo.InvariantCulture);
}
else if (!(Тип == typeof(System.DateTime)
|| Тип == typeof(System.String)
|| Тип == typeof(System.Decimal)
|| Тип.IsCOMObject)
)
obj = new AutoWrap(obj);
}
else
{
if (Тип.IsArray)
{
Type ТипМассива = Тип.GetElementType();
if (ТипМассива != null)
Тип = ТипМассива;
}
if (!(Тип.IsPrimitive
|| Тип == typeof(System.Decimal)
|| Тип == typeof(System.DateTime)
|| Тип == typeof(System.String)
|| Тип.IsCOMObject)
)
obj = new AutoWrap(obj);
}
}
return obj;
}
(9) похоже я не в теме, ничего не понимаю. Зачем нужно компоненту оборачивать, что это нам даст?
(10) куда передать? и откуда вернуть? если речь про обмен между компонентой и 1С, то возможна передача только простых типов и массива байтов, таковы ограничения технологии NativeAPI.
(11) пробовал я ByRef, не работает. Я знаю как по-другому сделать, но мне лень свои наработки выкладывать, тем более компонента не очень популярна.
Можно ли передать ссылку на ВК в качестве параметра. Если да то какой тип Варианта передается, и можно ли такой тип вернуть передав созданный наследник IComponentBase
Что бы обернуть реальный объект который например возвращает функция и через ВК выполнять его методы и свойства.
То есть вернуть ссылку и передать не получится? Или ссылку на ВК можно передать?
Тогда можно оборачивать например в двоичные данные структуру типа Variant, а из них доставать уже ссылки на объекты.
А ВК создавать через Новый куда передавать эти двоичные данные для инициализации ВК,
и если нужен объект в параметрах то передавать опять же эти ДД и из неё вытаскивать ссылку на реальный объект.
(13) это всё извращение (имхо), проще использовать обычный com-объект, написаный на c#. Я к компонентам вообще отношусь так: если можно сделать без компоненты, то лучше так и сделать, потому что потом кто это будет поддерживать?
(14) пробовал я c++/cli, CLR Hosting работает надежнее, сами 1Сники писали, что в таких смешанных сборках есть проблемы (не помню какие). Насчет CLR Hosting могу сказать, что её даже в MS SQL применяют для создания хранимых процедур CLR.
(15) импортозамещение в ПО достаточно условное, сам Linux пишут в америке в основном (если не ошибаюсь), поэтому под этими громкими словами скрывается простой смысл - не платить американцам за ПО. Core CLR еще не достаточно стабилен (судя по отзывам в инете). Тема конечно интересна, тем более xamarin Теперь бесплатный, можно писать на c# под разные платформы.
P.S. я не проф. разработчик на технологиях .NET, поэтому к моему мнению нужно относится с осторожностью.
На стороне .Net выполнять метод. Параметры передаются ввиде Stream. Сначало идет тип, затем данные. Возвращаемые объекты сохряняются в словаре и ID типа автоинкремента и передается тип как ссылочный и ИД.
В 1С мы можем возвращать Двоичные данные. Единственно, что byte[] мы тоже должны упаковывать и распаковывать
А не подскажешь как побороть ошибку при компиляции в VS 2015
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка C2371 int8_t: переопределение; различные базовые типы NETLoader \netloader\addin.netloader\include\types.h 67
вообще советую обновить все файлы из каталога include, т.к. с тех пор много чего изменилось, в компоненты была добавлена асинхронность, вроде бы шаблон собрали не 2010 студии, а на 2013.
(25) Serginio, как уже правильно заметили, тип такой определен. посмотри заголовчные файлы. у микрософта такой в заголовчнике есть, и скорее всего в заголовке у 1С в ВК. самое простое решение , это добавить к 1С typedef , signed.
(С++ не тот язык , который наскоком учится. в отличие от C#. советую почитать какие-нибудь книги. ошибки так и будут возникть, важно понимать причины их появления )
и советую установить английскую версию VS. просто потому что информацию по ошибкам будет проще искать.
(28) Ну С# тоже не наскоком. Там своих прибамбасов куча. А C++ просто отличается и куча нюансов. Сейчас в метро читаю. Занимательная штука. Время летит незаметно.
Кстати а есть полный аналог MemoryStream d C++. Или проще свой написать там недолго.
А насчет английской версии VS я уже понял. Идут кракозябры
Спасибо за обработку, успешно пользуемся уже почти год. Но, недавно столкнулись с одной очень странной проблемой. У клиента Windows server 2008, 1C Клиент-Сервер, база на SQL. На windows есть две учетки - Администратора системы и специальная учетка для службы 1С Агент(имя starter1C). Соответственно, на самом сервере мы можем работать с 1С под обеими учетками(просто указываем, где запускается обработка - на клиенте или на сервере), в то время как пользователи на удаленных машинах работают только под пользователем starter1C. В общем, если мы работает под администратором системы, все работает корректно, если под пользователем starter1C, то обработка крашится на функции CreateObject().
В чем причина так и не удалось понять, оба пользователя администраторы системы, по идее вся разница только в используемых Temp папках - C:\Users\<имя пользоваетля>\AppData\Local\Temp.
Помогите пожалуйста, было бы здорово разобраться с этим странным явлением:)
(31) Если под администратором работает, а под урезанной учеткой нет, то подозрение на права, наверное на каталог, который передается первым параметром в метод CreateObject
я давно еще добавил метод CreateObjectFromBase64(), в этом методе не используется каталог, а передается dll в виде строки (кодированной Base64), потом конвертируется в массив байтов и загружается в домен. Но есть небольшой минус - если есть зависимые dll, то их нужно зашивать в ресурсы (в случае загрузки из каталога CLR сама их загрузит). Приме во вложении.
(61) К сожалению, без изменений. Все также работает только первый метод - из каталога, два остальных метода на клиенте не работают... В общем-то не страшно, мы просто используем оба в зависимости от успешности его выполнения:)
Еще раз большое спасибо, все заработало, хотя и с некоторыми ограничениями. Компонента без зависимых dll подключилась нормально, в то время как состоящую из нескольких dll подключить так и не удалось. Не помогло даже сшивание их в единую dll с помощью программы ilMerge. Причем такое же ограничение возникло и при использовании второго метода загрузки - из временного файла.
(34) Все зависимые Dll должны быть в одной папке. Иногда даже требуется, что бы было все в директории 1С.
Если, что попробуй Как вызвать метод из C# в 1С?
(34) для обоих методов нужно использовать событие AssemblyResolve объекта AppDomain, смотри пример в проекте Test:
в ресурсы dll добавлена другая сборка System.Web.Helpers.dll, она загружается в домен в методе CurrentDomain_AssemblyResolve, а этот метод в свою очередь является обработчиком события AssemblyResolve.
(39) Спасибо! Я видел Вашу статью на хабре, я пока с линуксом не работаю, для меня это не актуально. NativeAPI хорош тем, что не надо ничего больше устанавливать, .NET Framework уже установлен на windows, и поэтому им уже сейчас можно пользоваться, а CoreCLR нужно устанавливать.
(43) а зачем мне это нужно?)) Денег это не приносит, известность тоже, публикация судя по звездам популярностью не пользуется.
Вообще те методы давно добавлены, просто лень было обновлять публикацию, вот решил обновить не знаю зачем. Вообще у меня есть еще наработки, но т.к. требуется время, чтобы всё это оформить и выложить, а пользы не предвидится, то и не хочется этим заниматься.
(44) I_G_O_R, Добрый день, использую ваш код и вот хочу выложить на github компоненту работы с RabbitMQ (C#) с NetLoader по лицензией LGPL 3.0. Если вы не против, добавлю вас как автора к исходным кодам NETLoader.
(55)Добрый день!
Не думал, что придется писать вам, так как до недавнего времени компонента работала корректно.Но, внезапно выяснилось, что на некоторых машинах компонента не работает, если ее запускать в контексте клиента.
Сама компонента NETLoader загружается, но при вызове метода CreateObjectFromBase64 возникает исключение, также поле CurrentVersionCLR не доступно. При этом, если запускать в контексте сервера, все нормально.
Как ни странно, функция GetInstalledRuntimes() работает нормально везде.
Пытался, как-то отследить зависимость ошибки, но на двух разных машинах с одинаковой ос (windows server 2008) и версией платформы, ошибка проявляется только на одной машине.
При этом, если использовать метод загрузки из временной папки CreateObject, то все нормально.
Не знаю будете ли вы разбираться с этим, но просто сообщил о такой ситуации.
Автор, выручай плз, подскажи как выкрутиться.
ps.метод в моей компоненте возвращает 1С'ке многомерный массив "multidimensional array <double>" .
На этом моменте 1С ругается на ошибку, так понимаю что с многомерными массивами Netloader не работает.
(48) не работает, потому что сама технология NativeAPI подразумевает обмен только простыми типами.
Нужно вернуть простой тип, например сериализовать массив в строку используя формат XML, JSON, CSV и т.д.
А в 1С потом можно десериализовать одним из встроенных методов.
Я делал лично так: в 1С создаешь нужный объект (в данном случае массив), сериализовал его с помощью объекта СериализаторXDTO, посмотрел какой получился текст, в компоненте в лоб сделал такой же текст (используя StringBuilder) и вернул получившуюся строку. в 1С потом с помощью объекта СериализаторXDTO обратно десериализовал.
процедуры для сериализации/десериализации:
Функция СериализоватьВXML(Значение)
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, Значение);
СтрокаXML = ЗаписьXML.Закрыть();
Возврат СтрокаXML;
КонецФункции
Функция ДесериализацияИзXML(СтрокаXML)
ЧтениеXML = Новый ЧтениеXML();
ЧтениеXML.УстановитьСтроку(СтрокаXML);
Значение = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
ЧтениеXML.Закрыть();
Возврат Значение;
КонецФункции
(49) I_G_O_R, спасибо. Попробую сериализацию, пока для тестов ограничился созданием паблик массива и методом из 1С'ки который в цикле, заполняет массив компоненты и получает из него данные.
А как считаете правильнее/быстрее?
Ведь в случае с сериализацией: на стороне 1с надосериализовать начальные данные(массив) в строку, затем строку опять сериализовать на стороне компоненты в массив c#. И обработанные данные также возвращать 1С т.е снова сериализовывать на компоненте передать 1с и сериазовать в тип 1с.
В случае обьявления в компоненте доступных массивов: Входящие данные и Результирующие данные и метода для установки/получения данных массива по индексу из 1С.
Множественные вызовы компоненты из 1С для получения значений, но не быстрее ли так чем с сериализацией или какие подводные камни могут быть.
(50) честно не знаю, тестировать надо, если мало данных, то я думаю, что это непринципиально, сделайте как удобнее. Вызов метода компоненты тоже не очень быстрый, т.к. там несколько прослоек.
Спасибо что сообщили. Но, честно говоря, даже не знаю в какую сторону копать...
Хотя возможно дело в том, что когда добавили асинхронность в 1С, в компоненте тоже что-то поменялось. В версии 8.3.8 был обновлен шаблон компоненты для поддержки асинхронности и я тоже выложил перекомпилированную компоненту. Вы используете последнюю версию? Версия 1С какая (8.3.7, 8.3.8)?
(58) Хотелось бы узнать у вас по поводу асинхронности.
Допустим, у меня во внешней компоненте будут выполняться долгие по времени вычисления. В данном случае, можно ли воспользоваться асинхронным вызовом ВК, чтобы интерфейс у пользователя не замораживался?
(60) В платформе 1С асинхронность поддерживается только на клиенте, и то формально, по факту интерфейс блокируется (8.3.9 я не проверял еще).
Чтобы не блокировался интерфейс, придется реализовывать что-то подобное: в компоненте запускать другой поток и в нем выполнять все действия. А чтобы понять, что действие выполнено, придется периодически опрашивать компоненту (т.к. поддержка внешних событий в текущей версии компоненты отсутствует). Т.е. вместо одного метода придется делать два: один запускает выполнение в другом потоке, второй проверяет выполнение и если надо возвращает результат.
(69) сама компонента написана на с++, в ней как раз используется один такой способ, называется Hosting CLR API, исходный код открыт, посмотрите как реализовано.