.NET(C#) для 1С. Динамическая компиляция класса обертки для использования .Net событий в 1С через ДобавитьОбработчик или ОбработкаВнешнегоСобытия
Разработка - Разработка внешних компонент
Эта статья является дополнением разработки Использование сборок .NET в 1С 7.x b 8.x находящейся здесь //firstportal.ru/public/238584/
Как то раз пришлось написать интеграцию 1С с WhatsApp. А там порядка 30 событий.
В ручную это делать было муторно как для обертки событий, так и для использования их в 1С.
Не поленился и написал кодогенератор.
Рассмотрим генерацию кода на примере System.IO.FileSystemWatcher
https://msdn.microsoft.com/ru-ru/library/system.io.filesystemwatcher(v=vs.110).aspx
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks;
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("6821a54a-19a2-4e66-85d9-e65396958080")]
public interface IВрапперДляSystem_IO_FileSystemWatcher
{
[DispId(0x00000001)]
void ОшибкаСобытия(Stringсобытие, object value, objectисключение);
[DispId(0x00000002)]
void Changed(object value);
[DispId(0x00000003)]
void Created(object value);
[DispId(0x00000004)]
void Deleted(object value);
[DispId(0x00000005)]
void Error(object value);
[DispId(0x00000006)]
void Renamed(object value);
[DispId(0x00000007)]
void Disposed(object value);
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("c3919804-ff5f-4d2a-a773-5067a1e051e1")]
[ComSourceInterfaces(typeof(IВрапперДляSystem_IO_FileSystemWatcher))]
public class ВрапперДляSystem_IO_FileSystemWatcher
{
[ComVisible(false)]
public delegate void Событие_Delgate();
[ComVisible(false)]
public delegate void СобытиеСПараметром_Delgate(object value);
[ComVisible(false)]
public delegate void СобытиеСПараметрами_Delgate(Stringсобытие, object value, objectисключение);
public System.IO.FileSystemWatcher РеальныйОбъект;
dynamic AutoWrap;
private SynchronizationContext Sc;
public event СобытиеСПараметрами_Delgate ОшибкаСобытия;
public Exception ПоследняяОшибка;
public event СобытиеСПараметром_Delgate Changed;
public event СобытиеСПараметром_Delgate Created;
public event СобытиеСПараметром_Delgate Deleted;
public event СобытиеСПараметром_Delgate Error;
public event СобытиеСПараметром_Delgate Renamed;
public event СобытиеСПараметром_Delgate Disposed;
private Object thisLock = newObject();
void ОтослатьСобытие(Событие_Delgate Событие, string ИмяСобытия)
{
Task.Run(() =>
{
if (Событие != null) //Событие();
{
lock (thisLock)
{
try
{
Sc.Send(d => Событие(), null);
}
catch (Exception ex)
{
try
{
Sc.Send(d => ОшибкаСобытия(ИмяСобытия, null, AutoWrap.ОбернутьОбъект(ex)), null);
}
catch (Exception)
{
}
}
}
}
});
}
void ОтослатьСобытиеСПараметром(СобытиеСПараметром_Delgate Событие, object value, string ИмяСобытия)
{
Task.Run(() =>
{
if (Событие != null) //Событие();
{
lock (thisLock)
{
try
{
Sc.Send(d => Событие(AutoWrap.ОбернутьОбъект(value)), null);
}
catch (Exception ex)
{
try
{
Sc.Send(d => ОшибкаСобытия(ИмяСобытия, AutoWrap.ОбернутьОбъект(value), AutoWrap.ОбернутьОбъект(ex)), null);
}
catch (Exception)
{
}
}
}
}
});
}
public ВрапперДляSystem_IO_FileSystemWatcher(object AutoWrap, System.IO.FileSystemWatcher РеальныйОбъект)
{
if (SynchronizationContext.Current == null)
SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
Sc = SynchronizationContext.Current;
this.РеальныйОбъект = РеальныйОбъект;
this.AutoWrap = AutoWrap;
РеальныйОбъект.Changed += (sender, e) =>
{
ОтослатьСобытиеСПараметром(Changed, new { sender = sender, e = e }, "Changed");
};
РеальныйОбъект.Created += (sender, e) =>
{
ОтослатьСобытиеСПараметром(Created, new { sender = sender, e = e }, "Created");
};
РеальныйОбъект.Deleted += (sender, e) =>
{
ОтослатьСобытиеСПараметром(Deleted, new { sender = sender, e = e }, "Deleted");
};
РеальныйОбъект.Error += (sender, e) =>
{
ОтослатьСобытиеСПараметром(Error, new { sender = sender, e = e }, "Error");
};
РеальныйОбъект.Renamed += (sender, e) =>
{
ОтослатьСобытиеСПараметром(Renamed, new { sender = sender, e = e }, "Renamed");
};
РеальныйОбъект.Disposed += (sender, e) =>
{
ОтослатьСобытиеСПараметром(Disposed, new { sender = sender, e = e }, "Disposed");
};
}
public static object СоздатьОбъект(object AutoWrap, System.IO.FileSystemWatcher РеальныйОбъект)
{
return new ВрапперДляSystem_IO_FileSystemWatcher(AutoWrap, РеальныйОбъект);
}
}
Так для упрощения, если параметров больше одного они упаковываются в анонимный класс.
Для вызова событий вызывается один из двух метод для всех событий с параметром и без.
Для вызова события в 1С используется SynchronizationContext для вызова в потоке 1С приложения.
Используется синхронизация на всякий случай и при возникновении ошибки при вызове метода 1С вызывается событие ОшибкаСобытия, так как такие ошибки 1С 8.х не отлавливает без секции попытка-исключение.
Параметры оборачиваются в объект типа AutoWrap с помощью AutoWrap.ОбернутьОбъект для использования объектов Net как объектов автоматизации
Модуль для 8 ки формируется такой
Перемврап,ОберткаСобытий;
Процедура СоздатьОбертку(объект)
//Динамически компилируется модуль C#
ОберткаСобытий=врап.СоздатьОберткуДляСобытий(объект);
// Добавляются обработчики
ДобавитьОбработчик ОберткаСобытий.ОшибкаСобытия,ОшибкаСобытия;
ДобавитьОбработчик ОберткаСобытий.Changed, Changed;
ДобавитьОбработчик ОберткаСобытий.Created, Created;
ДобавитьОбработчик ОберткаСобытий.Deleted, Deleted;
ДобавитьОбработчик ОберткаСобытий.Error, Error;
ДобавитьОбработчик ОберткаСобытий.Renamed, Renamed;
ДобавитьОбработчик ОберткаСобытий.Disposed, Disposed;
КонецПроцедуры
// Дается описание параметров, чтобы было проще к ним обращаться
//ИмяСобытия:String Имя События в котором произошло исключение
//Данные:object Параметры события
//ИсключениеСобытия:Exception Ошибка произошедшая при вызове события
Процедура ОшибкаСобытия(ИмяСобытия,Данные,ИсключениеСобытия)
Сообщить("Не обработано событие "+ИмяСобытия);
Сообщить(" Исключение "+Врап.ВСтроку(ИсключениеСобытия));
Сообщить(" Данные "+Врап.ВСтроку(Данные));
КонецПроцедуры
// параметр Данные:Аннимный Тип
// Свойства параметра
// sender:System.Object
// e:System.IO.FileSystemEventArgs
Процедура Changed(Данные)
Сообщить("Changed "+Врап.ВСтроку(Данные));
КонецПроцедуры
// параметр Данные:Аннимный Тип
// Свойства параметра
// sender:System.Object
// e:System.IO.FileSystemEventArgs
Процедура Created(Данные)
Сообщить("Created "+Врап.ВСтроку(Данные));
КонецПроцедуры
// параметр Данные:Аннимный Тип
// Свойства параметра
// sender:System.Object
// e:System.IO.FileSystemEventArgs
Процедура Deleted(Данные)
Сообщить("Deleted "+Врап.ВСтроку(Данные));
КонецПроцедуры
// параметр Данные:Аннимный Тип
// Свойства параметра
// sender:System.Object
// e:System.IO.ErrorEventArgs
Процедура Error(Данные)
Сообщить("Error "+Врап.ВСтроку(Данные));
КонецПроцедуры
// параметр Данные:Аннимный Тип
// Свойства параметра
// sender:System.Object
// e:System.IO.RenamedEventArgs
Процедура Renamed(Данные)
Сообщить("Renamed "+Врап.ВСтроку(Данные));
КонецПроцедуры
// параметр Данные:Аннимный Тип
// Свойства параметра
// sender:System.Object
// e:System.EventArgs
Процедура Disposed(Данные)
Сообщить("Disposed "+Врап.ВСтроку(Данные));
КонецПроцедуры
Так как в 7.7 нет возможности использования комовских событий, сделал обертку с использование вызова IAsyncEvent метода ExternalEvent
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks;
[Guid("ab634004-f13d-11d0-a459-004095e1daea"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAsyncEvent
{
void SetEventBufferDepth(int lDepth);
void GetEventBufferDepth(refint plDepth);
void ExternalEvent(string bstrSource, string bstrMessage, string bstrData);
void CleanBuffer();
}
public class ВрапперДляSystem_IO_FileSystemWatcher77
{
System.IO.FileSystemWatcher РеальныйОбъект;
publicobject Changed;
publicobject Created;
publicobject Deleted;
publicobject Error;
publicobject Renamed;
publicobject Disposed;
dynamic AutoWrap;
private SynchronizationContext Sc;
IAsyncEvent СобытиеДля1С;
privateObject thisLock = newObject();
public object ПоследняяОшибка;
public ВрапперДляSystem_IO_FileSystemWatcher77(object AutoWrap, ObjectГлобальныйКонтекст, System.IO.FileSystemWatcher РеальныйОбъект)
{
СобытиеДля1С = ГлобальныйКонтекст as IAsyncEvent;
if (SynchronizationContext.Current == null)
SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
Sc = SynchronizationContext.Current;
this.РеальныйОбъект = РеальныйОбъект;
this.AutoWrap = AutoWrap;
РеальныйОбъект.Changed += (sender, e) =>
{
Changed = new { sender = sender, e = e };
ОтослатьСобытие("Changed");
};
РеальныйОбъект.Created += (sender, e) =>
{
Created = new { sender = sender, e = e };
ОтослатьСобытие("Created");
};
РеальныйОбъект.Deleted += (sender, e) =>
{
Deleted = new { sender = sender, e = e };
ОтослатьСобытие("Deleted");
};
РеальныйОбъект.Error += (sender, e) =>
{
Error = new { sender = sender, e = e };
ОтослатьСобытие("Error");
};
РеальныйОбъект.Renamed += (sender, e) =>
{
Renamed = new { sender = sender, e = e };
ОтослатьСобытие("Renamed");
};
РеальныйОбъект.Disposed += (sender, e) =>
{
Disposed = new { sender = sender, e = e };
ОтослатьСобытие("Disposed");
};
}
void ОтослатьСобытие(string ИмяСобытия)
{
Task.Run(() =>
{
lock (thisLock)
{
try
{
Sc.Send(d => СобытиеДля1С.ExternalEvent("System_IO_FileSystemWatcher", ИмяСобытия, ""), null);
}
catch (Exception ex)
{
try
{
ПоследняяОшибка = new { Событие = ИмяСобытия, Исключение = ex };
Sc.Send(d => СобытиеДля1С.ExternalEvent("System_IO_FileSystemWatcher", "ОшибкаСобытия", ""), null);
}
catch (Exception)
{
}
}
}
});
}
public static object СоздатьОбъект(object AutoWrap, Object ГлобальныйКонтекст, System.IO.FileSystemWatcher РеальныйОбъект)
{
return new ВрапперДляSystem_IO_FileSystemWatcher77(AutoWrap, ГлобальныйКонтекст, РеальныйОбъект);
}
}
Для каждого события с параметром, параметрами создается одноименное поле и при возникновении события можно из 1С обратиться к этим полям.
Отмечу, что в данном случае объекты не оборачиваются в AutoWrap, так как обертка возвращается как AutoWrap. Поясню чуть позже
Перемврап,ОберткаСобытий;
Функция СоздатьОбертку(ОбертываемыйОбъект)
// В NetObjetToIDispatch.dllреализованклассВКpublicclassGlobalContext1C :IInitDone, ILanguageExtender
//для получения глобального контекста при вызове
// publicvoid Init([MarshalAs(UnmanagedType.IDispatch)]
// object connection)
// {
// глобальныйКонтекст = connection;
// Marshal.GetIUnknownForObject(глобальныйКонтекст);
// }
ПодключитьВнешнююКомпоненту("AddIn.GlobalContext1C");
объект = СоздатьОбъект("AddIn.GlobalContext1C");
ГлобальныйКонтекст= объект.ГлобальныйКонтекст;
ОберткаСобытий= врап.СоздатьОберткуДляСобытий77(ОбертываемыйОбъект,ГлобальныйКонтекст);
КонецФункции // СоздатьОбертку
// Свойства ОберткаСобытий.ПоследняяОшибка
//Событие:String Имя События в котором произошло исключение
//Данные:object Параметры события
//ИсключениеСобытия:Exception Ошибка произошедшая при вызове события
Функция ОшибкаСобытия()
ПоследняяОшибка=ОберткаСобытий.ПоследняяОшибка;
Сообщить("Не обработано событие "+ПоследняяОшибка.Событие);
Сообщить(Врап.ВСтроку(Шаблон("[ОберткаСобытий." + ПоследняяОшибка.Событие+ "]")));
Сообщить("Ошибка");
Сообщить(врап.ВСтроку(ПоследняяОшибка.Исключение))
КонецФункции
// Свойства ОберткаСобытий.Changed
// sender:System.Object
// e:System.IO.FileSystemEventArgs
Функция Changed()
Сообщить("Changed "+Врап.ВСтроку(ОберткаСобытий.Changed));
КонецФункции
// Свойства ОберткаСобытий.Created
// sender:System.Object
// e:System.IO.FileSystemEventArgs
Функция Created()
Сообщить("Created "+Врап.ВСтроку(ОберткаСобытий.Created));
КонецФункции
// Свойства ОберткаСобытий.Deleted
// sender:System.Object
// e:System.IO.FileSystemEventArgs
Функция Deleted()
Сообщить("Deleted "+Врап.ВСтроку(ОберткаСобытий.Deleted));
КонецФункции
// Свойства ОберткаСобытий.Error
// sender:System.Object
// e:System.IO.ErrorEventArgs
Функция Error()
Сообщить("Error "+Врап.ВСтроку(ОберткаСобытий.Error));
КонецФункции
// Свойства ОберткаСобытий.Renamed
// sender:System.Object
// e:System.IO.RenamedEventArgs
Функция Renamed()
Сообщить("Renamed "+Врап.ВСтроку(ОберткаСобытий.Renamed));
КонецФункции
// Свойства ОберткаСобытий.Disposed
// sender:System.Object
// e:System.EventArgs
Функция Disposed()
Сообщить("Disposed "+Врап.ВСтроку(ОберткаСобытий.Disposed));
КонецФункции
Процедура ПриОткрытии()
врап=СоздатьОбъект("NetObjectToIDispatch45");
КонецПроцедуры // ПриОткрытии
//======================================================================
Процедура ОбработкаВнешнегоСобытия(Источник, ИмяСобытия, Данные)
Если Источник = "System_IO_FileSystemWatcher" Тогда
Шаблон("[" + ИмяСобытия+ "()]");
КонецЕсли;
КонецПроцедуры // ОбработкаВнешнегоСобытия
Динамическая компиляция происходит следующим образом
public class КомВраперДляСобытий<T>
{
private static MethodInfo cоздательОбертки = null;
private static MethodInfo cоздательОбертки77 = null;
static CompilerResults СкомпилироватьОбертку(string строкаКласса,string ИмяКласса)
{
bool ЭтоСборкаГак = typeof(T).Assembly.GlobalAssemblyCache;
string Путь = Path.GetDirectoryName(typeof(T).Assembly.Location);
string OutputAssembly = Path.Combine(Путь, ИмяКласса) + ".dll";
var compiler = new CSharpCodeProvider();
var parameters = new CompilerParameters();
parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("System.Core.dll");
parameters.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
parameters.ReferencedAssemblies.Add(typeof(AutoWrap).Assembly.Location);
if (!ЭтоСборкаГак)
parameters.ReferencedAssemblies.Add(typeof(T).Assembly.Location);
else
{
string ИмяСборки = typeof(T).Assembly.ManifestModule.Name;
if (parameters.ReferencedAssemblies.IndexOf(ИмяСборки) == -1)
parameters.ReferencedAssemblies.Add(ИмяСборки);
}
if (ЭтоСборкаГак)
parameters.GenerateInMemory = true;
else
{ // parameters.GenerateInMemory = true;
parameters.GenerateInMemory = false;
parameters.OutputAssembly = OutputAssembly;
}
parameters.GenerateExecutable = false;
parameters.IncludeDebugInformation = true;
var res = compiler.CompileAssemblyFromSource(parameters, строкаКласса);
return res;
}
public static MethodInfo СоздательОбертки { get {
if (cоздательОбертки==null)
{
Type типРеальногоОбъекта = typeof(T);
string ТипСтрРеальногоОбъекта = типРеальногоОбъекта.FullName;
var ИмяКласса = "ВрапперДля" + ТипСтрРеальногоОбъекта.Replace(".", "_").Replace("+", "_");
string строкаКласса = ДляСозданияМодуляВрапера.СоздатьОписания(типРеальногоОбъекта);
var res = СкомпилироватьОбертку(строкаКласса,ИмяКласса);
Type тип = res.CompiledAssembly.GetType(ИмяКласса);
MethodInfo mi = тип.GetMethod("СоздатьОбъект", new Type[]{typeof(object),типРеальногоОбъекта });
cоздательОбертки = mi;
}
return cоздательОбертки;
} }
public static MethodInfo СоздательОбертки77
{
get
{
if (cоздательОбертки77 == null)
{
Type типРеальногоОбъекта = typeof(T);
string ТипСтрРеальногоОбъекта = типРеальногоОбъекта.FullName;
var ИмяКласса = "ВрапперДля" + ТипСтрРеальногоОбъекта.Replace(".", "_").Replace("+", "_")+"77";
string строкаКласса = ДляСозданияМодуляВрапера.СоздатьОписания77(типРеальногоОбъекта);
var res = СкомпилироватьОбертку(строкаКласса, ИмяКласса);
Type тип = res.CompiledAssembly.GetType(ИмяКласса);
MethodInfo mi = тип.GetMethod("СоздатьОбъект", new Type[] { typeof(object), typeof(object), типРеальногоОбъекта });
cоздательОбертки77 = mi;
}
return cоздательОбертки77;
}
}
Так, чтобы лишний раз не компилировать, закэшируем результат компиляции через свойство дженерик класса. Реализацию этого класса Net будет создавать при первом обращении, а статические поля будем заполнять компиляцией динамически создаваемого модуля на C# только раз для каждого типа.
Так, для GAC сборок можно компилировать сборку в памяти. Для не гаковских сборок нужно указывать путь, где лежит сборка оборачиваемого типа.
Вызов из 1С происходит с помощью 2 методов СоздатьОберткуДляСобытий или СоздатьОберткуДляСобытий77
MethodInfo ПолучитьMethodInfoОберткиСобытий(string ИмяСвойства, object РеальныйОбъект)
{
// получаем дженерик тип КомВраперДляСобытий<> и указывем тип
Type тип = РеальныйОбъект.GetType();
Type genType = typeof(КомВраперДляСобытий<>);
Type constructed = genType.MakeGenericType(new Type[] { тип });
// Nowнаходим свойство и получаем его значение
PropertyInfo pi = constructed.GetProperty(ИмяСвойства);
MethodInfo функция = (MethodInfo)pi.GetValue(null, null);
return функция;
}
public object СоздатьОберткуДляСобытий(object объект)
{
object РеальныйОбъект = AutoWrap.ПолучитьРеальныйОбъект(объект);
var функция = ПолучитьMethodInfoОберткиСобытий("СоздательОбертки", РеальныйОбъект);
object обертка = функция.Invoke(null,new object[] { this,РеальныйОбъект });
// Возвращаем реальный объект, так как он является COM объектом
return обертка;
}
public object СоздатьОберткуДляСобытий77(object объект, object ГлобальныйКонтекст)
{
object РеальныйОбъект = AutoWrap.ПолучитьРеальныйОбъект(объект);
var функция = ПолучитьMethodInfoОберткиСобытий("СоздательОбертки77", РеальныйОбъект);
object обертка = функция.Invoke(null, new object[] {ГлобальныйКонтекст,РеальныйОбъект });
// Оборачиваем обертку событий в AutoWrap для использования в 1С как объекта автоматизации
return AutoWrap.ОбернутьОбъект(обертка);
}
Кроме того, можно использовать DynamicMethod. В отличие от динамической компиляции сборки, определяет и представляет динамический метод, который может быть скомпилирован, выполнен и удален.Удаленные методы доступны для сборки мусора.
Так, в 1С нет операторов для битовых операций. Для работы с FileSystemWatcher
Нам нужно определить события которые мы хотим отслеживать. На C# это выглядит так.
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
Создадим функцию в C# проекте
public static NotifyFilters OR(NotifyFilters val1, NotifyFilters val2)
{
return val1 | val2;
}
Скомпилирует
В ILSpyнайдемнашметодивыберемязыкдекомпиляции IL
.method public hidebysig static
valuetype [System]System.IO.NotifyFilters OR (
valuetype [System]System.IO.NotifyFilters val1,
valuetype [System]System.IO.NotifyFilters val2
) cil managed
{
// Method begins at RVA 0x20cc
// Code size 9 (0x9)
.maxstack 2
.locals init (
[0] valuetype [System]System.IO.NotifyFilters
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: or
IL_0004: stloc.0
IL_0005: br.s IL_0007
IL_0007: ldloc.0
IL_0008: ret
} // end of method MainWindow::OR
Для получения кода на MSIL можно использовать:
Для рефлектора есть дизассемблер в Reflection.Emit, можно попытать щастья с expression trees (exp trees и emit состыковываются через CompileToMethod)
Также рекомендую вводную серию статей — тынц.
http://rsdn.ru/forum/dotnet/6235398.1
Большая благодарность Sinix
Так, используя старый Reflector и плагин ReflectionEmitLanguage.zip можно получить следующий код
public MethodBuilder BuildMethodOR(TypeBuildertype)
{
// Declaring method builder
// Method attributes
System.Reflection.MethodAttributes methodAttributes =
System.Reflection.MethodAttributes.Public
| System.Reflection.MethodAttributes.HideBySig
| System.Reflection.MethodAttributes.Static;
MethodBuildermethod = type.DefineMethod("OR", methodAttributes);
// Preparing Reflection instances
// Setting return type
method.SetReturnType(typeof(NotifyFilters));
// Adding parameters
method.SetParameters(
typeof(NotifyFilters),
typeof(NotifyFilters)
);
// Parameter val1
ParameterBuilderval1 = method.DefineParameter(1, ParameterAttributes.None, "val1");
// Parameter val2
ParameterBuilderval2 = method.DefineParameter(2, ParameterAttributes.None, "val2");
ILGeneratorgen = method.GetILGenerator();
// Preparing locals
LocalBuilderfilters = gen.DeclareLocal(typeof(NotifyFilters));
// Preparing labels
Labellabel7 = gen.DefineLabel();
// Writing body
gen.Emit(OpCodes.Nop);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Or);
gen.Emit(OpCodes.Stloc_0);
gen.Emit(OpCodes.Br_S,label7);
gen.MarkLabel(label7);
gen.Emit(OpCodes.Ldloc_0);
gen.Emit(OpCodes.Ret);
// finished
return method;
И соответственно напишем это все на языке 1С
Функция ПолучитьМетод()
//"System.Func`3"
NotifyFilters=врап.ПолучитьТип("System.IO.NotifyFilters");
helloArgs=врап.СоздатьМассив(врап.ПолучитьТип("System.Type"),2);
helloArgs.SetValue(NotifyFilters,0);
helloArgs.SetValue(NotifyFilters,1);
ТипДляМодуля=Врап.ТипКакОбъект(врап.ПолучитьТип("System.String"));
hello= врап.СоздатьОбъект("System.Reflection.Emit.DynamicMethod","OR",
NotifyFilters,
helloArgs,
ТипДляМодуля.Module);
il= hello.GetILGenerator();
il.DeclareLocal(NotifyFilters);
iL0007Label= il.DefineLabel();
OpCodes=врап.ПолучитьТип("System.Reflection.Emit.OpCodes");
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Or);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Br_S, iL0007Label);
il.MarkLabel(iL0007Label);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ret);
тип = врап.ПолучитьТип("System.Func`3");
типДелегата= Врап.ТипКакОбъект(тип).MakeGenericType(NotifyFilters,NotifyFilters,NotifyFilters);
res= hello.CreateDelegate(типДелегата
returnres
КонецФункции
Функция Или2(вал1,вал2)
возврат врап.ВыполнитьДелегат(ДелегатИЛИ,вал1,вал2);
//ДелегатИЛИ.DynamicInvoke(вал1,вал2);
КонецФункции// гл
Процедура КнопкаВыполнитьНажатие(Кнопка)
// Вставить содержимое обработчика.
Остановить();
watcher= врап.СоздатьОбъект("System.IO.FileSystemWatcher, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
Директория="c:\tmp\";
watcher.Path= Директория;
// Only watch text files.
ДелегатИЛИ=ПолучитьМетод();
NotifyFilters=врап.ПолучитьТип("System.IO.NotifyFilters");
//watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
// | NotifyFilters.FileName | NotifyFilters.DirectoryName;
рез=Или2(NotifyFilters.LastAccess,Или2(NotifyFilters.LastWrite,Или2(NotifyFilters.FileName,NotifyFilters.DirectoryName)));
watcher.NotifyFilter=рез;
watcher.Filter= "*.*";
watcher.IncludeSubdirectories= true;
watcher.EnableRaisingEvents= true;
СоздатьОбертку(watcher);
КонецПроцедуры
Так полностью можно исключить внешние сборки. Мало того, сейчас на подходе релиз scripting api.
https://joshvarty.wordpress.com/2015/10/15/learn-roslyn-now-part-14-intro-to-the-scripting-api/
http://daveaglick.com/posts/compiler-platform-scripting
То есть вместо IL можно использовать
То есть использование .Net в 1С станет достаточно простым.
Напоследок приведу пример использоваиня SerialPort для считывания Штрих-Кода
Процедура DataReceived(Данные)
sp1 = Данные.sender;
ШтрихКод= sp1.ReadExisting();
Компорт= sp1.PortName;
Сообщить(СтрШаблон("ШК=%1 Порт=%2",ШтрихКод,Компорт));
КонецПроцедуры
К проверял через SerialRedirectorиспользуя программы //firstportal.ru/public/14587/ .
Специальные предложения
См. также
Регистры бухгалтерии. Общая информация 111
05.09.2019 6698 YPermitin 22
"Хочу универсально!" [Часть 1] 65
02.09.2019 4900 SeiOkami 35
Иерархия без "В ИЕРАРХИИ" 117
22.08.2019 4913 ildarovich 16
EnterpriseData – часть 3. Загрузка данных, идентификация объектов 62
22.08.2019 4230 ids79 7
PinkRabbitMQ - Native API компонента 1С с открытым исходным кодом, для обмена сообщениями через RabbitMQ 137
29.07.2019 7140 445 Begemoth80 110
Обработчики событий при записи объектов. Зачем и что за чем? 202
25.07.2019 12801 4 AlbinaAAA 23
FizzBuzz на 1С. Чем короче, тем веселее. Варианты принимаются... 8
24.07.2019 2863 vandalsvq 16
Управление качеством кода 136
22.07.2019 8233 Stepa86 29
Что делает "В ИЕРАРХИИ" в запросе? 94
16.07.2019 8182 YPermitin 34
Создание отчетов с помощью СКД - основные понятия и элементы 208
25.06.2019 20978 ids79 17
Реализуем Стек, Очередь и Приоритетную очередь в 1С 52
24.06.2019 7804 RonX01 63
Вычисление 200 тысяч знаков числа pi 73
28.05.2019 3983 Oleg_nsk 93
Регистры накопления. Виртуальные таблицы. Часть №1: Обороты 84
20.05.2019 11069 YPermitin 5
Даем названия переменным: как префиксы экономят наше время 10
06.05.2019 3213 Designer1C 69
Заметки по SQL: Срез последних - аналог запроса 15
15.01.2019 6318 IVC_goal 5
Разработка и сценарное тестирование с Vanessa-ADD. Концепция, теория и сквозной пример создания сценария 222
09.01.2019 27568 Vladimir Litvinenko 69
Многопоточное восстановление последовательностей 41
05.12.2018 7248 _ASZ_ 29
Автоматические и управляемые блокировки применительно к типовым конфигурациям 1С 127
10.11.2018 22245 ids79 40
Основные понятия и механизмы оптимизации клиент-серверного взаимодействия в 1C 147
23.08.2018 22869 Rain88 42
Теорема номер тринадцать 15
15.03.2018 9358 vasilev2015 24
Введение в CI для 1С 87
21.11.2017 19331 real_MaxA 22
#Область ВНЕШНИЕ_ВЫЗОВЫ или MVC в 1С, библиотечность и упрощение интеграции кода 43
12.10.2017 14809 for_sale 58
Групповая разработка конфигураций в крупном холдинге 68
15.08.2017 17545 stas_ganiev 15
Автоматизация процесса 1С-разработки 91
07.06.2017 23028 ekaruk 9
Пишем игру Минер. Обработка событий ActiveX в 1С 29
29.05.2017 12732 user621724_Dimav1979 11
Как я доступ на kb.1c.ru получал 91
01.05.2017 22534 ikekoval 33
Улучшение стандарта "Структура модуля" 6
26.03.2017 12325 o.nikolaev 23
"Распределение в запросе" или "избавляемся от перебора" 185
16.12.2016 28631 alexandersh 48
Планы обмена. Квитировать или гарантировать? 24
12.12.2016 14558 zhichkin 9
Некоторые принципы оптимизации запросов 1С (+SQL) 115
17.11.2016 8898 ture 40
Использование git для доработки типовых конфигураций 1С 230
11.10.2016 188456 pumbaE 31
Оптимизация запросов 1С:Предприятие – от теории к практике 116
07.10.2016 32080 bpc222 20
.Net Core, обмен с 1C по TCP/IP между различными устройствами 15
28.09.2016 17645 Serginio 8
Net Core. Динамическая компиляция класса обертки для получения событий .Net объекта в 1С 8
14.09.2016 13527 Serginio 1
.Net Core, 1C, динамическая компиляция, Scripting API 10
07.09.2016 15836 Serginio 7
1С, Linux, Excel, Word, OpenXML, ADO, Net Core 31
22.08.2016 17286 51 Serginio 14
Асинхронное программирование в 1С через использование классов .Net из Native ВК 14
09.08.2016 14658 Serginio 3
Регистры сведений 1С. Как это устроено. 729
05.08.2016 151048 Sergey.Noskov 155
Переводим расширения на 8.3.8. Памятка. 79
29.07.2016 39710 mrXoxot 12
Подобие Объектно-ориентированного программирования в 1С (ПООПс) 12
24.07.2016 10916 adam26 54
Опыт практического применения методики BDD на 1С. Написание сценариев 121
03.07.2016 20335 oleynik.dv 132
Заметки про запросы. Последовательность. 110
27.05.2016 29630 vasilev2015 31
Оптимизация планирования доставки грузов. Алгоритм кластеризации k-means (метод K-средних). 26
10 стартмани
09.02.2016 26526 mi1man 4
Подсветка синтаксиса 1С в текстовых редакторах Atom, Sublime Text, VS Code 101
02.02.2016 23209 nixel 38
Использование классов .Net в 1С для новичков 147
27.01.2016 63758 Serginio 104
Контур.EDI изнутри, или история командной разработки тиражного продукта на 1С 174
17.11.2015 36044 skif47 88
Порядок записи движений регистров при проведении документа 95
13.11.2015 80528 triton_tver 8
Три способа получить дерево элементов иерархического справочника 52
11.11.2015 63125 32ops 9