Это продолжение статей
Использование сборок .NET в 1С 7.x b 8.x. Создание внешних Компонент. http://infostart.ru/public/238584/
Там же лежат и исходники
.NET(C#) для 1С. Динамическая компиляция класса обертки для использования .Net событий в 1С через ДобавитьОбработчик или ОбработкаВнешнегоСобытия
http://infostart.ru/public/417830/
1C Messenger для отправки сообщений, файлов и обмена данными между пользователями 1С, вэб страницы, мобильными приложениями а ля Skype, WhatsApp
http://infostart.ru/public/434771/
Использование классов .Net в 1С для новичков
http://infostart.ru/public/448668/
Написанием ВК я занимаюсь давно. Но никогда не писал напрямую.
Я никогда не понимал, зачем нужен IlanguageExtender, когда есть IDispatch.
Давным-давно сделал ВК, которая загружает Объект Автоматизации, поддерживающий ITypeInfo и выполняет все его свойства и методы через IlanguageExtender.
Смысл её в том, что пишем обычный COM класс, но для превращения её в ВК добавляем только один метод InitFrom1C. Например
public void InitFrom1C(object Object1C)
{
try
{
EventTo1C = Object1C as IAsyncEvent;
if (SynchronizationContext.Current == null)
SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
Sc = SynchronizationContext.Current;
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
throw e;
}
}
И вызов из 1С
Сообщить(ПодключитьВнешнююКомпоненту("AddIn.AddInFromITypeInfo"));
РаботаССоккетом = новый("AddIn.AddInFromITypeInfo");
// Соккет=New COMОбъект("ДляОбменаДаннмиЧерезTCP");
// РаботаССоккетом.LoadOleObject(Соккет);
РаботаССоккетом.LoadOleObject("ДляОбменаДаннмиЧерезTCP");
Если ИспользоватьКПК Тогда
Попытка
РаботаССоккетом.ОткрытьАйПиПортСНомеромПорта(ТСПАйПиНомерПорта);
Исключение
Сообщить("Нужно подключить новую TCPConnectTo1C.dll");
РаботаССоккетом.ОткрытьАйПиПорт();
КонецПопытки;
Сообщить(РаботаССоккетом.Команда);
Сообщить(РаботаССоккетом.ДанныеДляКоманды);
Если в 1С 7.7 через COMОбъект объект нельзя было в параметрах передавать объекты 1С и использовать out и ref параметры, то в восьмерке таких ограничений нет. И можно отказаться от обертки и передавать в Com объект только объект, передаваемый при вызове Init интерфейса IInitDone
public void Init([MarshalAs(UnmanagedType.IDispatch)]
object connection)
{
глобальныйКонтекст = connection;
Marshal.GetIUnknownForObject(глобальныйКонтекст);
}
Вот как это выглядит в 1С
врап=новыйCOMОбъект("NetObjectToIDispatch45");
Попытка
//Проверим зарегистрирована ли нужная версия NetObjectToIDispatch45
тест=НовыйCOMОбъект("AddIn.GlobalContext1C");
тест=Неопределено;
Исключение
ФайлNetObjetToIDispatch45=ЗаписатьМакет("NetObjectToIDispatch","NetObjetToIDispatch45");
ЗарегистрироватьDLL(ФайлNetObjetToIDispatch45);
КонецПопытки;
ФайлТестВК=ЗаписатьМакет("ТестВК");
Если ПодключитьВнешнююКомпоненту("AddIn.GlobalContext1C") Тогда
объект=Новый ("AddIn.GlobalContext1C");
ГлобальныйКонтекст=объект.ГлобальныйКонтекст;
AppDispatch=ГлобальныйКонтекст.AppDispatch;
AppDispatch.Сообщить("Привет");
Сообщить(AppDispatch.СтатусСообщения.Важное);
иначе
сообщить("Компонента не загружена");
КонецЕсли;
Кроме того, в 1С нельзя лего использовать Глобальный Контекст через AppDispatch
То есть AppDispatch.Сообщить(value)
ТипГК = ГК1С.GetType();
App1C = ГК1С.AppDispatch;
result = ТипГК.InvokeMember(binder.Name, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, App1C, new object[]{value}););
Для простоты использования я сделал оберку через
DynamicObject
Теперь можно легко использовать
public dynamic Новый( paramsobject[] Параметры)
{
return ГК.NewObject(Параметры);
}
public dynamic ПолучитьОписаниеТиповСтроки(int ДлинаСтроки)
{
return Новый(«ОписаниеТипов», «Строка», null, Новый(«КвалификаторыСтроки», ДлинаСтроки, ГК.ДопустимаяДлина.Переменная));
} // ПолучитьОписаниеТиповСтроки()
ГК.Сообщить(«Привет из ВК», ГК.СтатусСообщения.Важное);
Вот пример использования ГК и окон
Сборка=Врап.ЗагрузитьСборку(ФайлТестВК);
ТестВК=Сборка.GetType("ТестВК.ТестВК");
ТВК=Врап.СоздатьОбъект(ТестВК,ГлобальныйКонтекст);
Сообщить(ТВК.СоздатьОкно());
Использование окон WinForms и в особенности WPF позволяет использовать больший функционала, особенно при применении управляемого приложения.
Стоит отметить, что если для обычного приложения проходил такой код
тип=Врап.ПолучитьТипИзСборки("WPFLibrary.Window1",ФайлТестВК);
Окно=Врап.СоздатьОбъект(тип,ЭтотОбъект,ГлобальныйКонтекст);
Окно.Show();
То для управляемого приложения он не работает. Ошибка возвращаемого значениея.
Пришлось сделать статческий метод создания окна
Window1=Врап.ПолучитьТипИзСборки("WPFLibrary.Window1",ФайлТестВК);
Window1.СоздатьОкно(ЭтаФорма,ГлобальныйКонтекст);
Стоит отметить, что вместо использования ДобавитьОбработчик или ОбработкаВнешненго события
проще дать ссылку на модуль объекта или формы где прописать экспортные функции например
&НаКлиенте Процедура СообщитьСтр(стр) Экспорт
// Вставить содержимое обработчика. Сообщить(стр);
КонецПроцедуры
И вызывать из кода на C#
Модуль1С.СообщитьСтр(textBox.Text);
Ну и добавлю про использование немодального подключения ВК
&НаКлиенте
Процедура ПроверитьВК(Команда)
ProgID="AddIn.GlobalContext1C";
// Вставить содержимое обработчика.
Оповещение = Новый ОписаниеОповещения("УстановитьВК", ЭтотОбъект);
НачатьПодключениеВнешнейКомпоненты(Оповещение, ProgID);
КонецПроцедуры
&НаКлиенте
Процедура УстановитьВК(Подключено,Параметры) Экспорт
врап=новый COMОбъект("NetObjectToIDispatch45");
ProgID="AddIn.GlobalContext1C";
Попытка
Вк = Новый (ProgID);
Исключение
стр=ОписаниеОшибки();
ПоказатьПредупреждение(, "Компонента не подключена"+стр);
Возврат
КонецПопытки;
ГК=Вк.ГлобальныйКонтекст;
AppDispatch=ГК.AppDispatch;
AppDispatch.Сообщить("Привет");
Сообщить(AppDispatch.СтатусСообщения.Важное);
КонецПроцедуры
&НаКлиенте
Процедура ПриЗакрытии()
// Вставить содержимое обработчика.
ГлобальныйКонтекст=Неопределено;
Если ТВК<>Неопределено Тогда
ТВК.Закрыть();
ТВК=Неопределено;
КонецЕсли;
GC=Врап.ПолучитьТип("System.GC");
GC.Collect();
GC.WaitForPendingFinalizers();
Врап= Неопределено;
КонецПроцедуры
Спасибо, будет что почитать на досуге 🙂
Большое спасибо за спасибо.
Спасибо. Написано очень толково.
Я систематизировал свои знания по данному предмету, при помощи Вашей статьи.
Спасибо. Старался. Рад, что мои труды не пропадают зря.
Спасибо за статью. У меня com+ на с++ (Builder). Не совсем понимаю, как внутри этого объекта обратиться к глобальному контексту 1С. Объекты я передаю через VARIANT, например:
STDMETHODIMP TServerImpl::Make(VARIANT Object, int Numb, BSTR FileName)
{
bool Res=mycells->Make(Numb,AnsiString(WideString(FileName).c_bstr()));
Variant(Object).OleFunction(«Вставить»,»Ок»,(Res?»yes»:»no»));
return S_OK;
}
Но как получить доступ в этой функции к глобальному контексту 1С, чтобы вызвать, например, NewObject? Что передать на вход? Или можно как-то подключиться к самой 1С? Вопрос — как? Не через OLE же. И теоретически, этот com может быть использован и не 1С. Есть возможность проверить, кто его создал и использует?
Ну судя по
Показать
Адрес функции берется из VMT ГК1С, а в EAX засылается ГК1С.AppDispatch
Посмотриhttp://www.forum.mista.ru/topic.php?id=747688
Адреса Idispatch GetIDsOfName(), Invoke()
То есть ссылку на Idispatch берется из передаваемого объекта при Init, а объект подставляется AppDispatch
Помню в Delphi для реализации интерфейса создавалось поле внутри объекта, а в методах интерфейса были заглушки которые корректировали this по смещению поля и вызывали реальные методы интерфейса объекта
Лююююююди! Кто нибудь может накидать шаблон на Delphi, что бы можно было работать в глобальном контексте? C# вообще не понимаю, да и COM технология с трудом дается, но очень хочется пользоваться функционалом платформы, поэтому хотелось бы шаблон native-компоненты на Delphi. Я так понимаю для людей, оставивших здесь комментарии, это не составит никакого труда. Сейчас для написания внешних компонент пользуюсь шаблоном из публикацииhttp://infostart.ru/public/168254/ . Сжальтесь над немощным… ну что Вам стоит?
(10) Тебе лучше обратиться сюдаhttp://infostart.ru/public/88060/
Только вот глобальный Контекст это COM.
Я внедряю CefSharp во внешнюю компоненту. Сложность в том, что её не скомпилируешь в одну dll. У него множество файлов-зависимостей разных типов, без которых например подпроцесс для отображения содержимого страницы просто не запустится.
Когда эти файлы лежат рядом с запускаемым приложением, у меня всё работает. Но когда я компилирую библиотеку и подключаю её из 1С, у меня пустой экран как если бы подпроцесс не стартовал. Подозреваю, дело в зависимостях. Куда сложить файлы зависимостей чтобы они подтянулись к моей dll? Или может как-то иначе эти зависимости прописать в самой dll
Попробуй ILMerge
https://habr.com/post/126089/
https://github.com/Microsoft/ILMerge
На самом деле если все dll в одной папке и есть доступ к папке для текущего пользователя, то все должно быть нормально