Также добавлена возможность использования внешних событий в 1С, в том числе примеры обмена сообщениями по TCP/IP и Работа со сканером ШК, события отслеживание изменений в директории.
Примеры использование сборок для подключения к Вэб - сервисам, не поддерживаемые 1С. Использование конфигурационных файлов.
Реализацию ВК внутри сборки для получения Глобального контекста. Использование для установки владельца окна формы главного окна 1С,
вызов внешнего события, использование методов глобального контекста.
Так же добавил возможность показать окно семерки созданное через Новый COMОбъект("V77.Application");
Добавил динамическую компиляцию класса обертки для использования .Net событий через ДобавитьОбработчик или ОбработкаВнешнегоСобытия Статья по их использованию лежит здесь //infostart.ru/public/417830/
Реализация 1C Messenger описанного здесь //infostart.ru/public/434771/
Использование классов .Net в 1С для новичков //infostart.ru/public/448668/
Быстрое создание Внешних Компонент на C#. Примеры использования Глобального Контекста, IAsyncEvent, IExtWndsSupport, WinForms и WPF
//infostart.ru/public/457898/
.Net в 1С. Примеры использования HTTPClient, AngleSharp. Асинхронные HTTP запросы, отправка Post нескольких файлов multipart/form-data, сжатие трафика с использованием gzip, deflate, удобный парсинг сайтов и т.д //infostart.ru/public/466052/
.Net в 1С. На примере использования HTTPClient,AngleSharp.Удобный парсинг сайтов с помощью библиотеки AngleSharp в том числе с авторизацией аля JQuery с использованием CSS селекторов. //infostart.ru/public/466196/
Так же статья invertercant
Строка в дату. Универсальное решение. Применение NetObjetToIDispatch45 //infostart.ru/public/434345/
.Net в 1С. На примере использования HTTPClient,AngleSharp.Удобный парсинг сайтов с помощью библиотеки AngleSharp в том числе с авторизацией аля JQuery с использованием CSS селекторов. //infostart.ru/public/466196/
Кроссплатформенное использование классов .Net в 1С через Native ВК. Или замена COM на Linux //infostart.ru/public/534901/
Данная разработка создана для использования сборок .Net в 1С через преобразование объектов и классов в COM объекты которые можно использовать в 1С. Достигается это путем создания класса реализующим методы интерфейса
IReflect publi cclass AutoWrap : IReflect
Внутри него есть метод который оборачивает объекты не поддерживаемые в 1С в экземпляр класса AutoWrap.
Для облегчения работы с этим классом создан другой класс NetObjectToIDispatch
У него есть следующие методы
public object ПолучитьТип(string type)
Получает тип используя типы загруженных сборок полученный объект позволяет использовать статические методы класса
и члены перечислений примеры взятые отсюда
http://www.forum.mista.ru/topic.php?id=664174#62
http://dev.mista.ru/topic.php?id=686516
Пример отправки письма по протоколу Ssl
врап=новый COMОбъект("NetObjectToIDispatch45");
smtp = "smtp.yandex.ru";
login = "XXXXX@yandex.ru";
password = "XXXXXXX";
Кому = "XXXXXXX@YYYYYYYY.ru";
Port=25;
mail = врап.СоздатьОбъект("System.Net.Mail.SmtpClient",smtp, Port);
mail.EnableSsl = true;
mail.UseDefaultCredentials = false;
mail.Credentials = врап.СоздатьОбъект("System.Net.NetworkCredential",login, Password);
mail.DeliveryMethod = Врап.ПолучитьТип("System.Net.Mail.SmtpDeliveryMethod").Network;
Message = врап.СоздатьОбъект("System.Net.Mail.MailMessage");
MailAddressType= Врап.ПолучитьТип("System.Net.Mail.MailAddress");
Message.From = врап.СоздатьОбъект(MailAddressType,login);
Message.To.Add(врап.СоздатьОбъект(MailAddressType,Кому));
Message.Subject = "Тема Тест отправки почты SSL";
Message.IsBodyHtml = true;
Message.Body = "Тело Тест отправки почты SSL";
mail.Send(Message);//отправка
Message.Dispose();
mail.Dispose();
Но есть один минус: для типа нельзя вызвать методы типа. Для этого существует метод
public object ТипКакОбъект(object Тип)
из которого можно использовать методы и свойства Type (Например, AssemblyQualifiedName)
public object СоздатьОбъект(object Тип, paramsobject[] args)
Создает объект по типу или по строке, используя параметры, которые можно перечислять через запятую. Например
сервер=врап.СоздатьОбъект(тип,парам1,парам2);
public Object ChangeType(string type, object value)
Используя для преобразования типа в нужный тип. В C# используется перегрузка по параметрам. В .Net для чисел много типов, а 1С только один тип.
public object ПолучитьИнтерфейс(object obj, string InterfaseName)
получить интерфейс объекта.
public object ЗагрузитьСборку(string ПутьКСборке)
загружает сборку и возвращает ссылку на нё.
К сожалению, иногда не все методы выполняются. Например ToArray() для List
Или методы с параметром типа GUID (сам метод выполняется, но при передаче результата в 1С выдается ошибка «типы не совпадают» )
Для этого добавлен метод
public object ВыполнитьМетод(object obj, string ИмяМетода, params object[] args)
И вызов из 1С
//Ком=ЗагрузкаComОбъекта.ЗагрузитьОбъект(ИмяФайла,стр.Гуид); ошибка типа
Ком=Врап.ВыполнитьМетод(ЗагрузкаComОбъекта,"ЗагрузитьОбъект",ИмяФайла,стр.Гуид);
// Выполняется без ошибок
В Net особенно в WCF активно используются конфигурационные файлы.
Для использования их в 1С можно создать такой файл в директории запускаемой программы под именем ИмяЗапускаемойПрограммы.exe.config, например
C:\Program Files (x86)\1Cv77\BIN\1cv7s.exe.config
Или
C:\Program Files (x86)\1cv8\8.3.4.317\bin\1cv8.exe.config
Иногда стоит заменить этот файл на другой. Для этого есть метод
ЗаменитьConfigFile(string имяФайла)
Если имяФайла=”” тогда берется файл
typeof(NetObjectToIDispatch45).Assembly.Location + ".config"
Как пример показано программное изменение настроек
УстановитьDefaultProxy()
Другие методы созданы для отладки.
Также заложена возможность использования итераторов в 1С, например
рез= сервер.GetForms("Ваяся Пупкин");
Для каждого стр Из рез Цикл
сообщить(стр)
КонецЦикла;
Для использования в 1С 7.7 предусмотрено установка УстЭтоСемерка() так как в ней не поддерживается беззнаковые, Decimal и ограничена DateTime без времени.
Приведены примеры для 1С 7.7 и 8.3
Использующие сборку для доступа к Веб Сервису
http://www.morpher.ru/WebServices/Morpher.asmx
Использующие загрузку сборок, замену м модификацию конфигурационных файлов.
Вы можете создавать любые сборки или использовать стандартные библиотеки без регистрации.
NestNet45.dll для тестирования 4.5 TestWebServices.dll для тестов 2.0
Также добавлена возможность получения событий в 1С.
Для этого нужно создать сборку в которой создать делегаты и события
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Threading;
using System.Reflection;
namespace NetObjectToIDispatch45
{
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("33B45C9D-1AED-41F9-8880-36AB6AE84749")]
public interface IEventFor1C
{
[DispId(0x60020000)]
void Событие();
[DispId(0x60020001)]
void СобытиеСПараметром(object value);
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("62F8156C-13B9-4484-B152-82023243E1D3")]
[ComSourceInterfaces(typeof(IEventFor1C))]
public class ClassForEvent1C : System.Windows.Forms.UserControl
{
[ComVisible(false)]
public delegate void Событие_Delgate();
public delegate void СобытиеСПараметром_Delgate(object value);
public object Объект;
private SynchronizationContext Sc;
public ClassForEvent1C(object Объект,String СобытиеОбъекта,bool ЕстьПараметр=false)
{
this.Объект = Объект;
bf = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
EventInfo ei = Объект.GetType().GetEvent(СобытиеОбъекта, bf);
if (ЕстьПараметр)
ei.AddEventHandler(Объект,new System.Action(ВнешнееСобытие));
else
ei.AddEventHandler(Объект,new System.Action<object>(ВнешнееСобытиеСПараметром));
SynchronizationContext.SetSynchronizationContext(newWindowsFormsSynchronizationContext());
Sc =SynchronizationContext.Current;
}
public event Событие_Delgate Событие;
public event СобытиеСПараметром_Delgate СобытиеСПараметром;
private void ВнешнееСобытие()
{
if (this.Событие != null) //Событие();
Sc.Send(d => Событие(),null);
}
private void ВнешнееСобытиеСПараметром(object value)
{
if (this.СобытиеСПараметром != null) //Событие();
Sc.Send(d => СобытиеСПараметром(AutoWrap.ОбернутьОбъект(value)), null);
}
}
}
Использование в 1С
Перем ОбъектССобытием;
Процедура ТестСобытияНажатие(Элемент)
врап=новый COMОбъект("NetObjectToIDispatch45");
Сборка=врап.загрузитьСборку(ИмяФайлаСборки); //ПроектИспользованияДелегатов.dll
тип=Сборка.GetType("ПроектИспользованияДелегатов.КлассДляВнешнихСобытий");
ОбъектССобытием=врап.СоздатьОбъект(Тип,КаталогДляОтслеживанияИзменений);
Событие=Врап.ПолучитьОбъектДляСобытий(ОбъектССобытием,"Событие");
СобытиеПереименования=Врап.ПолучитьОбъектДляСобытий(ОбъектССобытием,"СобытиеПереименованияФайла");
ДобавитьОбработчик Событие.Событие, ПриИзмененииДиректории;
ДобавитьОбработчик СобытиеПереименования.Событие, ПриПереименованииФайла;
КонецПроцедуры
Процедура ПриИзмененииДиректории()
Сообщить(ОбъектССобытием.ИзмененныйФайл);
КонецПроцедуры
Процедура ПриПереименованииФайла()
Сообщить(ОбъектССобытием.ПереименованныйФайл);
КонецПроцедуры
Так же добавил сборку для обмена сообщениями по TCP/IP и сканера Штрих кода
В сборке ОбменПоTCPIP., при этом данные сжимаются GZip ом.
Пример использования на сервере
Функция СоздатьСерверTCP(Врап)
Если не ЗначениеЗаполнено(ИмяФайлаСборки) Тогда
вызватьИсключение "Не выбрано Имя Файла Сборки"
КонецЕсли;
врап=новый COMОбъект("NetObjectToIDispatch45");
ФайлСборки=ИмяФайлаСборки;//"d:\MyPrograms\Test\ОбменПоTCPIP\ОбменПоTCPIP\bin\Debug\ОбменПоTCPIP.dll";
Сборка=врап.загрузитьСборку(ФайлСборки); //ПроектИспользованияДелегатов.dll
тип=Сборка.GetType("TCPConnectTo1C.TCPConnector");
СерверTCP=врап.СоздатьОбъект(Тип);
возврат СерверTCP
КонецФункции // СоздатьTCP()
Процедура ЗапуститьСерверTCPIPНажатие(Элемент)
// Вставить содержимое обработчика.
перем Врап;
СерверTCP=СоздатьСерверTCP(Врап);
Событие=Врап.ПолучитьОбъектДляСобытийСПараметром(СерверTCP,"ПришлоСообщениеПоTCP");
ДобавитьОбработчик Событие.СобытиеСПараметром, ПолучениеДанныхПоTCP;
СерверTCP.ОткрытьАйПиПортСНомеромПорта(6891);
ЭлементыФормы.ОтправитьКоманду.Видимость=ложь;
КонецПроцедуры
Процедура ПолучениеДанныхПоTCP(Данные)
Сообщить("Команда="+Данные.Команда);
Сообщить("Данные="+Данные.Данные);
Сообщить("ЕстьОтвет="+Данные.ЕстьОтвет);
Если Данные.ЕстьОтвет Тогда
Ответ="Ответ на команду "+Данные.Команда+"
|Данные "+Данные.Данные+"
|ВремяНаСервере="+XmlСтрока(ТекущаяДата());
СерверTCP.Ответить(Ответ);
КонецЕсли;
КонецПроцедуры
На Клиенте
Процедура ОтправитьКомандуНажатие(Элемент)
перем Врап;
КлиентTCP=СоздатьСерверTCP(Врап);
ServerAdress="127.0.0.1";
порт=6891;
Команда="Тест Отправки Сообщения";
ДанныеДляКоманды=XmlСтрока(ТекущаяДата());
ЕстьОтвет=истина;
ЗакрытьСоединение=истина;
ОшибкаСоединения=false;
резулт=КлиентTCP.ОтправитьКоманду(ServerAdress,порт,Команда,ДанныеДляКоманды,ЕстьОтвет,ЗакрытьСоединение);
Сообщить(резулт.Данные);
Если резулт.ОшибкаСоединения Тогда
СтрОшибки="ОшибкаСоединения
|"+резулт.Данные;
Предупреждение(СтрОшибки);
КонецЕсли;
КонецПроцедуры
И добавлена работа со Сканером ШК. К сожалению проверить его работу не могу, ввиду отсутствия сканера
Процедура ОткрытьПортСканераНажатие(Элемент)
перем Врап;
// Вставить содержимое обработчика.
НомерПорта=0;
Если не ВвестиЧисло(НомерПорта,"Введите номе COM порта",4,0) Тогда
возврат
КонецЕсли;
СерверTCP=СоздатьСерверTCP(Врап);
Событие=Врап.ПолучитьОбъектДляСобытийСПараметром(СерверTCP,"ДанныеОтСканера");
ДобавитьОбработчик Событие.СобытиеСПараметром, ПолучениеДанныхПоTCP;
СерверTCP.ПодключитьСканер(НомерПорта);
КонецПроцедуры
Процедура ПолучениеДанныхОтСканераШК(Данные)
Сообщить("ИмяПорта="+Данные.ИмяПорта);
Сообщить("ШтрихКод="+Данные.Данные);
КонецПроцедуры
И добавлен приер загрузки объекта из DLL без регистрации на примере загрузки
Из comcntr.dll класс COMConnector. Для примера когда нужно подключиться к Базе с версией отличной от текущей
Добавил пример использования конфигурационного файла в WCF клиентах в DLL
public object СоздатьКлиентаWCFConfigFile(string ИмяФайла, object TChannel, string endpointConfigurationName, object endpointAddress)
{
ExeConfigurationFileMap fileMap = newExeConfigurationFileMap();
fileMap.ExeConfigFilename = ИмяФайла;
Configuration newConfiguration = ConfigurationManager.OpenMappedExeConfiguration(
fileMap,
ConfigurationUserLevel.None);
Type ТипКанала=ТипДляСоздатьОбъект(TChannel);
Type type= typeof(ConfigurationChannelFactory<>);
Type constructed = type.MakeGenericType(ТипКанала);
dynamic factory1 = System.Activator.CreateInstance(constructed,
endpointConfigurationName,
newConfiguration,
AutoWrap.ПолучитьРеальныйОбъект(endpointAddress)
);
return AutoWrap.ОбернутьОбъект(factory1.CreateChannel());
}
Процедура ВызовСервисаИспользуяConfigFileНажатие(Элемент) // Вставить содержимое обработчика. врап=новый COMОбъект("NetObjectToIDispatch45");
//Сборка=врап.загрузитьСборку("d:\MyPrograms\Test\NestNet45\NestNet45\bin\Debug\NestNet45.dll"); Сборка=врап.загрузитьСборку(ИмяФайлаСборки); TChannel=Сборка.GetType("NestNet45.ServiceReference1.MorpherSoap"); ConfigFile=ИмяФайлаСборки+".config"; endpointConfigurationName="MorpherSoap"; endpointAddress=Неопределено; Клиент=врап.СоздатьКлиентаWCFConfigFile(ConfigFile,TChannel,endpointConfigurationName,endpointAddress);
// Вызываю метод и вывожу результат рез = Клиент.GetForms("Ваяся Пупкин");
Для каждого стр Из рез Цикл сообщить(стр) КонецЦикла;
КонецПроцедуры
Подправил обертку объектов. Теперь массивы примитивных типов строки, дата, Decimal возвращаются как родные для 1С COMSafeArray.
Для массива объектов нужно отдельно преобразовать через функция
ПолучитьSafeArrayИзЭнумератора(Object Массив)
Так же при работе с событиями проще сделать комовский класс с событиями например
// Создаем интерфейс доступных событий из 1С
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IEventFor1C
{
[DispId(0x00000001)]
void Событие();
[DispId(0x00000002)]
void СобытиеПереименованияФайла(object ИмяДиректории);
}
// Указываем какие комовские события будет реализовывать класс
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComSourceInterfaces(typeof(IEventFor1C))]
public class КлассДляВнешнихСобытий2
{
public string ИзмененныйФайл;
public string ПереименованныйФайл;
public event System.Action Событие;
[ComVisible(false)]
public delegate void СобытиеСПараметром_Delgate(object value);
public event СобытиеСПараметром_Delgate СобытиеПереименованияФайла;
public FileSystemWatcher watcher;
dynamic Врапер;
private SynchronizationContext Sc;
private void ИзмененияВДиректории(object source, FileSystemEventArgs e)
{
// Specify what is done when a file is changed, created, or deleted.
ИзмененныйФайл = e.FullPath + " " + e.ChangeType;
if (this.Событие != null)
Sc.Send(d => Событие(), null);
}
// Врапер это объект который создается через
//врап=новый COMОбъект("NetObjectToIDispatch45");
// Нужен для обертки объектов в AutoWrap
public КлассДляВнешнихСобытий2(Object Врапер,string Директория)
{
this.Врапер=Врапер;
// SynchronizationContext нужен для того, что вызов проходил в потоке 1С
SynchronizationContext.SetSynchronizationContext(new System.Windows.Forms.WindowsFormsSynchronizationContext());
Sc = SynchronizationContext.Current;
watcher = new FileSystemWatcher();
watcher.Path = Директория;
/* Watch for changes in LastAccess and LastWrite times, and
the renaming of files or directories. */
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
// Only watch text files.
watcher.Filter = "*.*";
// Add event handlers.
watcher.Changed += new FileSystemEventHandler(ИзмененияВДиректории);
watcher.Created += new FileSystemEventHandler(ИзмененияВДиректории);
watcher.Deleted += new FileSystemEventHandler(ИзмененияВДиректории);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
// Begin watching.
watcher.IncludeSubdirectories = true;
watcher.EnableRaisingEvents = true;
}
private void OnRenamed(object source, RenamedEventArgs e)
{
// Specify what is done when a file is renamed.
ПереименованныйФайл = string.Format("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
if (this.СобытиеПереименованияФайла != null)
Sc.Send(d => СобытиеПереименованияФайла(Врапер.ОбернутьОбъект(ПереименованныйФайл)),null);
// В данном случае ПереименованныйФайл это строка и Врапер.ОбернутьОбъект(ПереименованныйФайл) для примера,
// что бы показать как обернуть любой объек в AutoWrap не читаемый из 1С Net объект
}
}
И соответственно вызов из 1С
врап=новый COMОбъект("NetObjectToIDispatch45");
Сборка=врап.загрузитьСборку(ИмяФайлаСборки); //ПроектИспользованияДелегатов.dll
тип=Сборка.GetType("ПроектИспользованияДелегатов.КлассДляВнешнихСобытий2");
ОбъектССобытием2=врап.СоздатьОбъект(Тип,врап,КаталогДляОтслеживанияИзменений);
// Нужен для доступа к комовским событиям
КомОбъектССобытием=Врап.ПолучитьРеальныйОбъект(ОбъектССобытием2);
ДобавитьОбработчик КомОбъектССобытием.Событие, ПриИзмененииДиректории;
ДобавитьОбработчик КомОбъектССобытием.СобытиеПереименованияФайла, ПриПереименованииФайла2;
При выходе можно очистить события.
Если ОбъектССобытием2<>Неопределено Тогда
врап.ОчиститьСобытияОбъекта(ОбъектССобытием2.watcher);
врап.ОчиститьСобытияОбъекта(ОбъектССобытием2);
КонецЕсли;
Добавил реализацию ВК внутри сборки для получения Глобального контекста. Использование
Если ПодключитьВнешнююКомпоненту("AddIn.GlobalContext1C") Тогда
объект=Новый ("AddIn.GlobalContext1C");
ГлобальныйКонтекст=объект.ГлобальныйКонтекст;
AppDispatch=ГлобальныйКонтекст.AppDispatch;
AppDispatch.Сообщить("Привет");
иначе
сообщить("Компонента не загружена");
КонецЕсли;
Использование Внутри Net.
public ТестВК(object Object1C)
{
this.Object1C = Object1C;
ГК = new ДинамикГК(Object1C);
}
public string СоздатьОкно() {
// m_1cApp.AppDispatch.Сообщить("Привет из ВК");
// не работает для упрощения работы создань динамический объект ДинамикГК
// выполняющий аналогичную фунцию
IExtWndsSupport n;
ГК.Сообщить("Привет из ВК", ГК.СтатусСообщения.Важное);
n = (IExtWndsSupport)Object1C;
IntPtr hwnd;
n.GetAppMainFrame(out hwnd);
// Создаем форму, устанавливаем нативные хэндлы и устанвливаем окно 1С владельцем нетовского окна
var form = new Form1();
form.CreateControl();
SetOwner(form.Handle.ToInt32(), hwnd.ToInt32());
form.EventTo1C = Object1C as IAsyncEvent;
form.Show();
return "Методы ВК выполнены!";
}
private async void button1_Click(object sender, EventArgs e)
{
var ПотокПриложения = Thread.CurrentThread.ManagedThreadId;
// Для чистоты эксперимента вызовим события из потока отличного от потока приложения.
// Что бы await не использовал текущий контекст установим ConfigureAwait(false)
await Task.Delay(1000).ConfigureAwait(false); // делаем задержку в секунду и вызываем событие
var ПотокСобытия = Thread.CurrentThread.ManagedThreadId;
// Для вызова в тотоке приложения вызовем метод из его потока
Sc.Send(d => EventTo1C.ExternalEvent("ДанныеИзТестВК", "Тест", string.Format("Поток Приложения={0} Поток события {1}",ПотокПриложения,ПотокСобытия)), null);
// Если очень быстро кликать по кнопке то потоки события будут разными
}
Также добавил возможность показать окно семерки созданное через Новый COMОбъект("V77.Application");