Использование классов .Net в 1С для новичков

Опубликовал Сергей Смирнов (Serginio) в раздел Программирование - Практика программирования

Руководство для новичков. Написав статью http://infostart.ru/public/238584/, я понял, что многие не понимают того, что написано. Поэтому в этой статье постараюсь более подробно остановиться на азах и без кода на вражеском языке (C#)

В  .Net есть классы, структуры(Value типы), перечисления. С точки зрения 1С их можно рассматривать как классы. Каждый класс характеризуется типом.

По аналогии с 1С классы это справочники, документы и т.д.

У классов могут быть статические методы и свойства  и методы и свойства объекта. По аналогии с 1С статические методы это методы менеджера (НайтиПоКоду,НайтиПоНомеру), а методы объекта аналогичны методам объекта (Модифицированность, Удалить, Номер,Дата)

У каждого класса есть тип, через который мы и будем работать. Для упрощения класс и тип для нас будет одним и тем же.

Каждый класс характеризуется именем класса, пространством имен и сборкой (размещение Dll, Exe).

Рассмотрим класс String https://msdn.microsoft.com/ru-ru/library/system.string(v=vs.110).aspx

Представляет текст как последовательность знаков Юникода.

Исходный код .NET Framework для этого типа см. в указанном источнике.

Пространство имен:   System
Сборка:  mscorlib (в mscorlib.dll)

Начнем сразу на примерах. Итак, для начала создадим объект, который будет обертывать объекты .Net в COM объекты.

врап=новый COMОбъект("NetObjectToIDispatch45");

Теперь получим тип System

String=Врап.ПолучитьТип("System.String");

Для понимания правильнее будет так

ПространствоИмен="System.";
String=Врап.ПолучитьТип(ПространствоИмен+"String");

Кто работал с ФабрикаXDTO, то там тоже есть простанство имен и типы.

К типам, которые находятся в GAC, мы можем не указывать сборку, в которой она находится.

КлассНеГак=Врап.ПолучитьТипИзСборки(ПолноеИмяКласса,ПолноеИмяФайла)

Теперь мы можем вызвать статические методы.

Например, аналог  1С функции ПустаяСтрока

Сообщить(String.IsNullOrWhiteSpace(неопределено));
Сообщить(String.IsNullOrWhiteSpace("  "));

Вернет Истина.

 

Статические методы в справке https://msdn.microsoft.com/ru-ru/library/system.string(v=vs.110).aspx

Помечаются  символом S.

К сожалению, есть проблемы с функциями, которые принимают параметры как массив params.

Например, у класса String  есть статическая функция Format

У неё есть множество перегрузок.

https://msdn.microsoft.com/ru-ru/library/b1csw23d(v=vs.110).aspx

public static string Format(

               string format,

               params object[] args

)

Которая вызывается, когда параметров больше 3

При объявлении  параметра как params object[] мы можем задавать параметры через запятую.

Сообщить(String.Format("загружено {0} из {1} байт. {2}  % complete...", 
        e.BytesReceived, 
        e.TotalBytesToReceive,
		e.ProgressPercentage,
        0));

Я добвил еще один неиспользуемый параметр 0, иначе последний параметр вывелся бы как System.Object[]

Для того, что бы исправлять такие ошибки я добавил  метод ВыполнитьМетод

Который принимает первым параметром тип или строковое представление типа ("System.String");

Вторым параметром имя метода, а дальше параметры для запрашиваемого метода

 

Сообщить(Врап.ВыполнитьМетод(String,"Format","загружено {0} из {1} байт. {2}  % complete...", 
        e.BytesReceived, 
        e.TotalBytesToReceive,
		e.ProgressPercentage));

Теперь перейдем с созданию объекта и вызову методов объекта.

Объект можно получить двумя способами

DateTime= Врап.ПолучитьТип("System.DateTime ");
Дата=Врап.СоздатьОбъект(DateTime,2015,1,2);

или

Дата=Врап.СоздатьОбъект("System.DateTime",2015,1,2);

Следует учесть, что в 1С числовые типы, дата строки, булево, массивы этих типов и Com объекты возвращаются как родные.

Поэтому если использовать объектные методы, например, String нужно обернуть его.

Например

ОбернутаяСтрока=Врап.ОбернутьЛюбойОбъект("Тестовая строка");

Теперь можно применить к ней объектные методы

Найдем первое вхождение строки "ст" начиная с 6 символа (Возвращает индекс с отсчетом от нуля первого вхождения значения указанной строки в данном экземпляре. Поиск начинается с указанной позиции знака.)

Сообщить(ОбернутаяСтрока.IndexOf("ст",5));

Вернет 9

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

http://professorweb.ru/my/csharp/charp_theory/level11/11_1.php

 

Возьмем для примера System.Collections.Generic.List<T>

https://msdn.microsoft.com/ru-ru/library/6sh2ey19(v=vs.110).aspx

 

В C# Для того, чтобы создать список строк

var список = new List<String>();
Можно посмотреть строковое представление класса
Список.GetType().ToString()
Или
typeof(List<String>).ToString();

 

он выдаст System.Collections.Generic.List`1[System.String]

Теперь мы можем использовать его

Список=Врап.СоздатьОбъект("System.Collections.Generic.List`1[System.String]");
Для сч=1 По 10 Цикл
Список.Add(строка(сч));	
КонецЦикла; 

Для каждого стр Из Список Цикл
	 Сообщить(стр)
КонецЦикла;

Но тоже можно добиться другим способом

Узнав строковое представление typeof(List<>).ToString()

System.Collections.Generic.List`1[T]

Оно совпадает с названием класса, только добавляется `1 это говорит, что дженерик поддерживает 1 неопределенный тип.

ListT=Врап.ПолучитьТип("System.Collections.Generic.List`1");
ListT=Врап.ТипКакОбъект(ListT); 
Список=Врап.СоздатьОбъект(ListT.MakeGenericType(String));

Нужно отметить, для того, что бы у объекта полученного как  ПолучитьТип был доступ к методам класса Type нужно его преобразовать через метод ListT=Врап.ТипКакОбъект(ListT);

Так как в реализации обертки он отвечает за статические методы класса.

Аналогично можно создать и словарь Dyctionary, это типизированный аналог 1С Соответствие

Dictionary<String,int>

Словарь= Врап.СоздатьОбъект("System.Collections.Generic.Dictionary`2[System.String,System.Int32]");

Для сч=1 По 10 Цикл

Словарь.Add(строка(сч),сч);	

КонецЦикла; 

Для каждого стр Из Словарь Цикл
	 Сообщить(стр.Key+"="+стр.Value)
КонецЦикла; 

//Аналогично это можно достигнуть через
СловарьT=Врап.ПолучитьТип("System.Collections.Generic.Dictionary`2");
Int32=Врап.ПолучитьТип("System.Int32");
СловарьT=Врап.ТипКакОбъект(СловарьT);
Словарь=Врап.СоздатьОбъект(СловарьT.MakeGenericType(String,Int32));

Еще одна особенность работы с C# реализацией this[]

Например, в 1С мы не можем вызвать Список[0]. Доступ осуществляется через

get_Itemи set_Item

Список.set_Item(0,"1С+Net");
Сообщить(Список.get_Item(0));

Вот полный список классовSystem.Collections.Generic

https://msdn.microsoft.com/ru-ru/library/system.collections.generic(v=vs.110).aspx

Регулярные выражения тоже часто применяются для поиска замены.

http://professorweb.ru/my/csharp/charp_theory/level4/4_10.php

Я покажу, как их использовать на примерах

input = "Добро пожаловать в наш магазин, вот наши цены: 
 |1 кг. яблок - 20 руб. 
 |2 кг. апельсинов - 30 руб.
 |0.5 кг. орехов - 50 руб.";
 
 pattern = "\b(\d+\W?руб)";
 regex = Врап.СоздатьОбъект("System.Text.RegularExpressions.Regex",pattern);
  // Получаем совпадения в экземпляре класса Match
 matches = regex.Matches(input);
// отображаем все совпадения
Для Каждого match in matches Цикл
	 // Т.к. мы выделили в шаблоне одну группу (одни круглые скобки),
	 // ссылаемся на найденное значение через свойство Groups класса Match
	 Сообщить(match.Groups.get_Item(1).Value);
КонецЦикла

В статье многого не затронешь, но хочу показать быстродействие вызова методов .Net классов через обертку.

В 1С нет явного аналога StringBuilder Предоставляет изменяемую строку символов.

В этом тесте нужно собрать строку из маленьких фрагментов строк. В 1С для соединения строк есть неявный аналог ЗаписьXML ЗаписатьБезОбработки.

Для  замера времени используем Stopwatch который замеряет время до миллисекунды

https://msdn.microsoft.com/ru-ru/library/system.diagnostics.stopwatch(v=vs.110).aspx

Процедура ВывестиВремя(врап,stopWatch)
	ts = stopWatch.Elapsed;
	String=Врап.ПолучитьТип("System.String");
	// Format and display the TimeSpan value.
	elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
	ts.Hours, ts.Minutes, ts.Seconds,
	ts.Milliseconds / 10,0);
	Сообщить(elapsedTime);
КонецПроцедуры	
Процедура StringBuilderНажатие(Элемент)
	// Вставить содержимое обработчика.
	врап=новый COMОбъект("NetObjectToIDispatch45");

	КоличествоИтераций=200000;
	stopWatch = Врап.СоздатьОбъект("System.Diagnostics.Stopwatch");
	
	стр="";
	
	НачВремя=ТекущаяДата();
	stopWatch.Start();
	
	Для сч=1 по КоличествоИтераций Цикл
		стр=стр+Строка(сч);
	КонецЦикла;
	stopWatch.Stop();
	
	ВремяВыполнения=ТекущаяДата()-НачВремя;
	Сообщить("Конкатенация ="+ВремяВыполнения+" сек. ДлинаСтр="+СтрДлина(Стр));
	
	ВывестиВремя(врап,stopWatch);
	стр="";
	НачВремя=ТекущаяДата();
	stopWatch.Restart();
	SB =  врап.СоздатьОбъект("System.Text.StringBuilder");
	Для сч=1 по КоличествоИтераций Цикл
		SB.Append(Строка(сч));
	КонецЦикла;
	
	стр=SB.ToString();
	stopWatch.Stop();
	
	ВремяВыполнения=ТекущаяДата()-НачВремя;
	Сообщить("StringBuilder ="+ВремяВыполнения+" сек. ДлинаСтр="+СтрДлина(Стр));
	ВывестиВремя(врап,stopWatch);
	
	НачВремя=ТекущаяДата();
	stopWatch.Restart();
	ЗаписьXML = Новый ЗаписьXML;
	ЗаписьXML.УстановитьСтроку();
	
	Для сч = 1 по КоличествоИтераций Цикл
		ЗаписьXML.ЗаписатьБезОбработки(Строка(сч));
	КонецЦикла;
	Стр = ЗаписьXML.Закрыть();
	stopWatch.Stop();
	
	ВремяВыполнения=ТекущаяДата()-НачВремя;
	Сообщить("ЗаписьXML ="+ВремяВыполнения+" сек. ДлинаСтр="+СтрДлина(Стр));
	ВывестиВремя(врап,stopWatch);
	
//Конкатенация =96 сек. ДлинаСтр=1 287 896
//00:01:36.22
//StringBuilder =10 сек. ДлинаСтр=1 287 896
//00:00:09.91
//ЗаписьXML =4 сек. ДлинаСтр=1 287 896
//00:00:04.40



КонецПроцедуры

Как видно, скорость вызова .Net класса в 2.25 раза медленнее обычного метода. Это нужно учитывать при обработке больших массивов данных.

Используем информацию о культуре .

https://msdn.microsoft.com/ru-ru/library/system.globalization.cultureinfo(v=vs.110).aspx

Но часто нужно получать с данных без учета культуры

Целое   = 55333;
Дробное   = 66333.44;
Строка   = "абвгд";
Дата=ТекущаяДата();

CultureInfo=Врап.ПолучитьТип("System.Globalization.CultureInfo");
SB.AppendFormat(CultureInfo.InvariantCulture,"{0} {1} {2} {3}",Целое,Дробное,Строка,Дата,0);
Сообщить(SB.ToString());

Получаем

55333 66333.44 абвгд 01/26/2016 17:10:05

Стоит еще добавить приведение типа к Интерфейсу. На примере прохода по коллекции. Если в 1С можно пройтись через Для Каждого то для 7 ки этого сделать нельзя. Заодно понять как приводить к интерфейсу.

Так из документации мы знаем что List<T> поддерживает интерфейс IEnumerable

https://msdn.microsoft.com/ru-ru/library/system.collections.ienumerable(v=vs.100).aspx

 Перечислимый=Врап.ПолучитьИнтерфейс(Список,"IEnumerable");
 Перечислитель=Перечислимый.GetEnumerator();
 // На всякий случай приведем к Интерфейсу IEnumerator
 Перечислитель=Врап.ПолучитьИнтерфейс(Перечислитель,"IEnumerator");
 // Теперь можем пройтись по коллекции
 
Пока Перечислитель.MoveNext() Цикл
//  Врап.ВСтроку вывоит строковое представление всех типов в том числе числовые, строки, неопределено
	Сообщить(Врап.ВСтроку(Перечислитель.Current));

КонецЦикла; 
// Для того что бы получить методы объекта реализующего интерфейс можно
// спомощью метода  ОбновитьДанныеОметодахИСвойствах(object objOrig)


// Для того что бы получить массив String[] можно вызвать
Массив=Список.ToArray();
 Сообщить(Массив);

 // В 1С он будет определен как COMSafeArray VT_BSTR
 // Доступ к элементам массива также как и в COMSafeArray через  GetValue и SetValue
//https://msdn.microsoft.com/library/system.array(v=vs.100).aspx
// Создать массив можно через метод врапера СоздатьМассив(object type, int length)

Еще в .Net для асинхронного программирования используют await и методы возвращающие Task<>

Для того, чтобы получить результат, нужно обратиться к свойству Result, если нужно подождать, то вызвать метод Wait()

https://msdn.microsoft.com/ru-ru/library/dd321424(v=vs.118).aspx

// Следует отметить, что не все типы из GAC модно подгрузить
// Например  System.Net.Http.HttpClient который находится с System.Net.Http.dll
//Получить тип можно двумя способами
// По полному имени 
//Клиент=Врап.СоздатьОбъект("System.Net.Http.HttpClient, System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
//Либо просто указать имя библиотеку в котором находится класс без полного пути
//Тогда  ПолучитьТипИзСборки будет искать в катаорге GAC
HttpClient=Врап.ПолучитьТипИзСборки("System.Net.Http.HttpClient","System.Net.Http.dll");
Клиент=Врап.СоздатьОбъект(HttpClient);
ДанныеРесурса=Клиент.GetStringAsync("https://msdn.microsoft.com/ru-ru/library/hh551745(v=vs.118).aspx").Result;

Сообщить(Врап.ВСтроку(ДанныеРесурса));

Стоит вспомнить про вложенные типы на примере System.Environment.SpecialFolder 

Так для получения типа нужно разделять вложенный тип знаком плюс, а не точкой

 

Environment=Врап.ПолучитьТип("System.Environment");
	SpecialFolder=Врап.ПолучитьТип("System.Environment+SpecialFolder");
	Сообщить(Environment.GetFolderPath(SpecialFolder.CommonProgramFilesX86));
	Сообщить(Environment.GetFolderPath(SpecialFolder.Desktop));
	Сообщить(Environment.GetFolderPath(SpecialFolder.MyDocuments));
 

Используя System.IO.Path можно получить доступ к Temp директории

Path=Врап.ПолучитьТип("System.IO.Path");
Сообщить(Path.GetTempPath());

Там же много методов для манимулирования с наименованием файла, получение каталога, расширения, объединять строки в путь итд

Очень часто приходится использовать битовую операци OR

например 

 AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
 
или
 watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
           | NotifyFilters.FileName | NotifyFilters.DirectoryName;
 
Поэтому добавил метод OR. Теперь те же операции можно вызвать
 
DecompressionMethods= Врап.ПолучитьТип("System.Net.DecompressionMethods");
  handler.AutomaticDecompression=Врап.OR(DecompressionMethods.GZip,DecompressionMethods.Deflate) ;

или

NotifyFilters=врап.ПолучитьТип("System.IO.NotifyFilters");
    рез=Врап.OR(NotifyFilters.LastAccess,NotifyFilters.LastWrite,NotifyFilters.FileName,NotifyFilters.DirectoryName);
 

Надеюсь, данная статья поможет использовать классы .Net даже тем, кто не знает C#. Ничего сложного нет, но поможет сильно увеличить возможности 1С без написания COM объектов или ВК

См. также

Добавить вознаграждение
Комментарии
1. Сергей Смирнов (Serginio) 499 27.01.16 17:43 Сейчас в теме
Сейчас в .Net широко применяют оператор await. Он применяется к методам возвращающие Task или Task<TResult>.
Task это задача представляет асинхронную операцию. Доступ к результату осуществляется через свойство Result.
В 1С можно использовать либо синхронный вариант например
ДанныеРесурса=Клиент.GetStringAsync("https://msdn.microsoft.com/ru-ru/library/hh551745(v=vs.118).aspx").Result;


Но для того, что бы этот метод выполнить асинхронно я создал класс с помощью которого легко использовать эти методы асинхронно.

врап=новый COMОбъект("NetObjectToIDispatch45");
Выполнитель=Врап.ПолучитьАсинхронныйВыполнитель();
ДобавитьОбработчик Выполнитель.ПриОкончанииВыполненияЗадачи, ПриОкончанииВыполнения;

Обработчик события выглядит так
Процедура ПриОкончанииВыполнения(Задача,ДанныеКЗадаче)

    // Обязательно нужно отлавливать ошибку в 1С
    // Иначе она передается в .Net где обрабатывается там
    Попытка
Так как задача может завершиться с ошибкой
Мы должны проверить, и если ошибка нужно предпринять какие то действия
        Если (Задача.IsFaulted) Тогда  // Ошибка выполнения

            Сообщить("Ошибка "+Врап.ВСтроку(Задача.Exception));
            Сообщить("Данные к задаче "+Врап.ВСтроку(ДанныеКЗадаче));

        иначе
            Сообщить("=====Выполнена задача ====");
            Сообщить("Данные к задаче "+Врап.ВСтроку(ДанныеКЗадаче));
            Сообщить(Врап.ВСтроку(Задача.Result));


        КонецЕсли;

    Исключение
        Сообщить("Ошибка в процедуре");
        Сообщить(ОписаниеОшибки());
    КонецПопытки

КонецПроцедуры
...Показать Скрыть

Вызываем задачу так
HttpClient=Врап.ПолучитьТипИзСборки("System.Net.Http.HttpClient","System.Net.Http.dll");
    Клиент=Врап.СоздатьОбъект(HttpClient);
    Задача=Клиент.GetStringAsync("https://msdn.microsoft.com/ru-ru/library/hh551745(v=vs.118).aspx");
    Выполнитель.Выполнить(задача,ТекущаяДата());
...Показать Скрыть

Вторым параметром можно передавать любые данные, что бы понять какая задача выполнена и что с ней делать, так одновременно может работать множество задач

Например

АсинхМетоды = Врап.СоздатьОбъект(КлассДляТестаАсинхронныхМетодов);

    Для сч=1 по 10 Цикл
        задача=АсинхМетоды.ДолгаяЗадача(Строка("Задача "+сч));
        Выполнитель.Выполнить(задача,сч);
    КонецЦикла
...Показать Скрыть
2. Константин Юрин (kostyaomsk) 65 28.01.16 18:02 Сейчас в теме
Интересная статья. Надо будет запомнить для задач интеграции. Жаль, что приводится то что не очень надо :( А хотелось бы иметь под рукой библиотеку функций допустим для работы с зависшими процессами (фоновыми задачами), многими функциями ОС итд.
Кстати насчет времени до миллисекунд вроде стандартная консоль запросов содержит строчку на JavaScript для записи текущего времени.
3. Константин Юрин (kostyaomsk) 65 28.01.16 18:05 Сейчас в теме
Вернее автору статьи (и знающим людям) вопрос по-другому: я могу вызвать API-функции Винды смотря справочник через данные объекты просто смотря справочник, передавать в функции и принимать от них данные в формате винды (или в универсальном формате). Я когда-то давно начинал с делфи, даже на ассемблере чуток писал для аппаратуры, но сейчас это в прошлом. Тогда только через стандарные компоненты делфи работал.
Чтоб не было голословно приходилось писать только на досовском C++ Может навык пригодится для хотя бы понимания как обратиться к современным библиотекам на C# .net или что там
Прикрепленные файлы:
CH.C
TEST.C
4. Сергей Смирнов (Serginio) 499 28.01.16 18:22 Сейчас в теме
(2) Ну эта статья для начинающих. Посмотри мои другие статьи. Там много других примеров. Все написать невозможно. Показан принцип работы с классами .Net . Просто нужно найти нужный, а примеров в инете правда на C# полно.
(3) Не понял?
5. Константин Юрин (kostyaomsk) 65 28.01.16 19:01 Сейчас в теме
(4) Serginio, это большой плюс что Вы описали в двух словах "как запустить". Тем более я в этой технологии и есть "начинающий". Хотелось бы узнать кратно что можно и нужно делать через .net если:
1. Такой технологии НЕТ в 1С.
2. Стандартные методы сложны, глючны и малоэффективны.
На что в общем стоит обратить внимание.
6. Сергей Смирнов (Serginio) 499 28.01.16 23:34 Сейчас в теме
(5) Я бы посоветовал начать с азов. От простого к сложному.
http://metanit.com/sharp/general.php
http://professorweb.ru/my/csharp/charp_theory/level1/infonet.php

Для начала просмотреть, а уже на конкретных задачах углубляться.
7. Андрей Суровов (Andris_infostart) 03.02.16 12:37 Сейчас в теме
(2) kostyaomsk, ТекущаяУниверсальнаяДатаВМиллисекундах(), вполне подходит для получения мс
8. Олег (olbu) 04.02.16 14:51 Сейчас в теме
Интересно!, а есть простые примерчики применения?
9. Сергей Смирнов (Serginio) 499 04.02.16 15:40 Сейчас в теме
10. Александр (Ferroks) 17.02.16 13:32 Сейчас в теме
Недавно столкнулся с преобразование типов, за 5 минут задачу решить не получилось)
Оставлю здесь подсказку.

Преобразовании типов 1С в типы Net

Г
УИД = СОКРЛП(Новый УникальныйИдентификатор());
UUU = Врап.ПолучитьТип("System.Guid").Parse(ГУИД);
Дата = ТекущаяДата();
	
	
ЧислоИНТ1 = Врап.ChangeType("System.Int32",-2147483648);
ЧислоИНТ2 = Врап.ChangeType("System.Int32",2147483647);
Десятичное1 = Врап.ChangeType("System.Decimal",7.9 * Pow(10,28));                              
Десятичное2 = Врап.ChangeType("System.Decimal",-7.9 * Pow(10,28));
Дробное1	=	Врап.ChangeType("System.Decimal","0.000001");
Дробное2 	= Врап.ChangeType("System.Decimal","-0.0000001");
...Показать Скрыть
11. Александр (Ferroks) 17.02.16 13:41 Сейчас в теме
можно еще так преобразовать тип 1С в тип Net
ТипДесЧерезПарсе = Врап.ПолучитьТип("System.Decimal").Parse("0,000001");

бывает что получаешь ошибку "Неизвестная ошибка" или метод не найдет, проверьте параметр который передаете.
ТипДесЧерезПарсе = Врап.ПолучитьТип("System.Decimal").Parse("0,000001");
- так отрабатывает нормально.
а так выдает ошибку - ТипДесЧерезПарсе = Врап.ПолучитьТип("System.Decimal").Parse("0.000001");
12. Игорь Богданов (avz_1C) 10 17.02.16 14:28 Сейчас в теме
Простите, а как узнать длину строки через свойство Length переменной типа String?

Я создал строку:

врап=новый COMОбъект("NetObjectToIDispatch45");
ПространствоИмен="System.";
String=врап.ПолучитьТип(ПространствоИмен+"String");
стр = String("abc");


Отработало нормально, в переменной стр находится "abc"

Теперь добавляю

ДлинаСтр = стр.Length;


и получаю ошибку:

"Значение не является значением объектного типа (Length)"
13. Сергей Смирнов (Serginio) 499 17.02.16 14:34 Сейчас в теме
(11) Как я писал в статье для таких случаев нужно использовать CultureInfo

Decimal=Врап.ПолучитьТип("System.Decimal");
   CultureInfo=Врап.ПолучитьТип("System.Globalization.CultureInfo");
   culture=CultureInfo.InvariantCulture;
   Число="0.000001";
   Сообщить(Decimal.Parse(Число, culture.NumberFormat));
...Показать Скрыть
14. Сергей Смирнов (Serginio) 499 17.02.16 14:36 Сейчас в теме
(12) В статье писал про это

Следует учесть, что в 1С числовые типы, дата строки, булево, массивы этих типов и Com объекты возвращаются как родные.

Поэтому если использовать объектные методы, например, String нужно обернуть его.

Например
ОбернутаяСтрока=Врап.ОбернутьЛюбойОбъект("Тестовая строка");
ДлинаСтр =ОбернутаяСтрока.Length; 

...Показать Скрыть



15. Игорь Богданов (avz_1C) 10 17.02.16 14:41 Сейчас в теме
Получилось так:

врап = Новый COMОбъект("NetObjectToIDispatch45");
стр = врап.ОбернутьЛюбойОбъект("1СдотНЕТ");
ДлСтр = стр.Length;


В ДлСтр значение 8

При попытке посмотреть отладчиком 1С структуру объекта стр, система ругается на множество сборок.
16. Игорь Богданов (avz_1C) 10 17.02.16 14:43 Сейчас в теме
Не успел прочитать ответ, увидел в статье и тут же попробовал.
О результате сообщил постом выше.
Спасибо!
17. Игорь Богданов (avz_1C) 10 17.02.16 14:46 Сейчас в теме
Через МИСТА, по ссылке на яндекс-диск, получил проект (исходники) от NetObjectToIDispatch.dll версии 2.0

А можно ли где-то взять проект (исходники) NetObjectToIDispatch45.dll ?

Ну, очень интересная тема.
18. Сергей Смирнов (Serginio) 499 17.02.16 14:58 Сейчас в теме
19. Игорь Богданов (avz_1C) 10 17.02.16 16:20 Сейчас в теме
Спасибо. Получил.
Если, вдруг, потребуются "соучастники" в проект, готов поработать.
Под Вашим руководством :-)
20. Сергей Смирнов (Serginio) 499 17.02.16 16:48 Сейчас в теме
(19) Спасибо. Буду иметь ввиду. Но самое лучшее это писать статьи как http://infostart.ru/public/434345/
21. Игорь Богданов (avz_1C) 10 17.02.16 18:34 Сейчас в теме
Буду пытаться. Благодарю Вас за совет.
Да и Вы, если вдруг захотите расширить аудиторию, милости
просим в авторы блога на сайт www.programmist1c.ru
22. Сергей Смирнов (Serginio) 499 18.02.16 09:41 Сейчас в теме
(21) Спасибо буду иметь ввиду
23. Игорь Богданов (avz_1C) 10 18.02.16 15:02 Сейчас в теме
Добрый день, Сергей.

Тестирую Вашу обработку ТестВКУФ.erf

Захватывающе! Особенно с окном на WPF.

Очень хочется посмотреть исходники того, что упаковано в двоичный макет.

Можно?

И вот, ещё, встретил в статье след. предложение:
- "Также добавил возможность показать окно семерки созданное через Новый COMОбъект("V77.Application")

А это в каком примере можно увидеть?

Прошу прощения, если что-то пропустил, но, вроде бы читал внимательно.
24. Игорь Богданов (avz_1C) 10 18.02.16 15:56 Сейчас в теме
При повторном, начиная с третьего, открытии обработки, через Файл -> Открыть ... Появляется сообщение:

- "Неизвестное имя формы: ХХХХХХХХХХХХХХХХХХХХХХХХ.Form"

Пока не разобрался, в чем дело.

Предполагаю, что-то связанное с кэшем.

25. Сергей Смирнов (Serginio) 499 18.02.16 16:34 Сейчас в теме
(23) Я же давал ссылку в 18. Исходники лежат в папке ТестВК
26. Сергей Смирнов (Serginio) 499 18.02.16 16:41 Сейчас в теме
Только там в public partial class Window1 : Window
нужно добавить

public static void СоздатьОкно(dynamic модуль1С, dynamic Object1C)
        {
            модуль1С.СообщитьСтр("Зашли в метод");
            var окно = new Window1(модуль1С, Object1C);
            окно.Show();
            модуль1С.СообщитьСтр("Форма открыта");
        }
...Показать Скрыть
27. Сергей Смирнов (Serginio) 499 18.02.16 16:57 Сейчас в теме
28. Игорь Богданов (avz_1C) 10 18.02.16 18:21 Сейчас в теме
(25) Serginio,

Да, спасибо. Нашел эту папку.
29. Игорь Богданов (avz_1C) 10 18.02.16 18:22 Сейчас в теме
(26) Serginio,

Спасибо, понял.

Сейчас попытаюсь.
30. Игорь Богданов (avz_1C) 10 18.02.16 18:44 Сейчас в теме
(27) Serginio,

Да, все получилось. Метод СоздатьОкно(dynamic модуль1С, dynamic Object1C)

работает отлично.

Ошибка с диагнозом

"Неизвестное имя формы: ХХХХХХХХХХХХХХХХХХХХХХХХ.Form"

не появляется при запуске в тонком клиенте.
31. Сергей Смирнов (Serginio) 499 19.02.16 10:13 Сейчас в теме
(30) Большое спасибо за использование и тестирование. Помню в 7 ке окно показывалось в списке окон, но при нажатии 1С вылетала. Видно 1С смотрит дочерние окна, но чужое окно она разрулить не может. Посмотрю.
32. Игорь Богданов (avz_1C) 10 19.02.16 17:14 Сейчас в теме
Спасибо за Ваш труд.

Никак не наиграюсь :-)

От перспектив захватывает дух.

Кстати, на *NIX-ах надо бы попробовать.

Вероятно, на Linux должно пойти, через Mono?

Или Mono не увидит под собой технологическую базу для Com Interop?

Хотя, вот тут говорят, что можно ...

http://www.mono-project.com/docs/advanced/pinvoke/

Надо потестировать.
33. Сергей Смирнов (Serginio) 499 19.02.16 17:26 Сейчас в теме
Эта библиотека основана на преобразование .Net объектов в IDispatch через Ireflect. На линуксе не взлетит
34. Сергей Смирнов (Serginio) 499 20.02.16 14:32 Сейчас в теме



Очень часто приходится использовать битовую операци OR

например
 AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate



или
 watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite| NotifyFilters.FileName | NotifyFilters.DirectoryName;





Поэтому добавил метод OR. Теперь те же операции можно вызвать

DecompressionMethods= Врап.ПолучитьТип("System.Net.DecompressionMethods");
  handler.AutomaticDecompression=Врап.OR(DecompressionMethods.GZip,DecompressionMethods.Deflate) ;

или

NotifyFilters=врап.ПолучитьТип("System.IO.NotifyFilters");
    рез=Врап.OR(NotifyFilters.LastAccess,NotifyFilters.LastWrite,NotifyFilters.FileName,NotifyFilters.DirectoryName);


35. Сергей Смирнов (Serginio) 499 21.02.16 08:12 Сейчас в теме
Пример алгоритма сжатия строки и результат в Base64 и обратный процесс

стр = "Строка для теста компрессии декомпрессии";
	
	// Получим используемые типы
	MemoryStream=Врап.ПолучитьТип("System.IO.MemoryStream");
	UTF8=Врап.ПолучитьТип("System.Text.Encoding").UTF8;
	CompressionMode = врап.ПолучитьТип("System.IO.Compression.CompressionMode");
	
	
	СжатыйПоток = врап.СоздатьОбъект(MemoryStream); //Поток куда запишутся сжатые данные
	
	
	zipStr = врап.СоздатьОбъект("System.IO.Compression.GZipStream", СжатыйПоток, CompressionMode.Compress);
	
	МассивДанных= UTF8.GetBytes(стр);// Получим массив данных используя кодировку  UTF8
	ПотокДляСжатия = Врап.СоздатьОбъект(MemoryStream,МассивДанных);  // Создадим поток из массива данных

	ПотокДляСжатия.CopyTo(zipStr);
	zipStr.Flush(); // Сбросим данные в  СжатыйПоток
	zipStr.Close(); // Закроем  GZipStream
	compressed = СжатыйПоток.ToArray(); // Получим массив байт сжатых данных

	Convert=Врап.ПолучитьТип("System.Convert");
	стр64=Convert.ToBase64String(compressed); // Переведем сжатые данные в Base64
	//Сообщить(стр64);
...Показать Скрыть



и обратный процесс


//===== Процесс разжатия данных из строки кодированной алгоритмом Base64	
	
compressed=Convert.FromBase64String(стр64);

ПотокСжатыхДанных = врап.СоздатьОбъект(MemoryStream,compressed);
GZipПоток =врап.СоздатьОбъект("System.IO.Compression.GZipStream",ПотокСжатыхДанных, CompressionMode.Decompress);
ПотокРазжатыхДанных = врап.СоздатьОбъект(MemoryStream);
GZipПоток.CopyTo(ПотокРазжатыхДанных);
Данные=ПотокРазжатыхДанных.ToArray();
 output = UTF8.GetString(Данные);

	Сообщить(output);
...Показать Скрыть
36. Сергей Смирнов (Serginio) 499 26.02.16 16:11 Сейчас в теме
(32) Это вызов натива из манагед.
А вот обратно нужно что типа CLR Hosting API
37. Игорь Богданов (avz_1C) 10 26.02.16 19:22 Сейчас в теме
(36) Пытался провернуть такое на .NET Compact Framework 3.5 ...
Не взлетело.
38. Сергей Смирнов (Serginio) 499 26.02.16 19:33 Сейчас в теме
39. Игорь Богданов (avz_1C) 10 27.02.16 15:32 Сейчас в теме
(38) Приходится работать с CF3.5, так как на ТСД Motorola Symbol (все остальные бренды - копии той или иной степени копийности) в основном установлены Windows CE или Windows Mobile. Пока только китайские китайцы пытаются клепать ТСД и прочие POS девайсы на Windows Phone 8 и даже Windows 10. Нет желающих переделывать отлаженные логистические цепочки под использование экспериментальных образцов. Нет заказчиков - нет разработок.
40. Сергей Смирнов (Serginio) 499 27.02.16 17:28 Сейчас в теме
(39) Согласен у самого под рукой Casio под Win CE. C Compact FW конечно пришлось повозиться. Но когда появились наработки затем писать уже намного легче.
41. Игорь Богданов (avz_1C) 10 28.02.16 15:29 Сейчас в теме
(40) И, может быть, хорошо, что в промышленном оборудовании (ТСД например) нет такого стремительного мелькания техники и технологий, как в товарах группы "Б". Иначе бы все рухнуло. Доля консерватизма необходима в группе "А", не может быть базис текучим и непредсказуемым.
42. Сергей Смирнов (Serginio) 499 15.03.16 14:52 Сейчас в теме
Понадобилоссь прописать дефолтный принтер в 7 ке

врап=СоздатьОбъект("NetObjectToIDispatch45"); 

    врап.УстЭтоСемерка();
    

Registry=Врап.ПолучитьТип("Microsoft.Win32.Registry");


Ключ="Software\1C\1Cv7\7.7\ИмяБазы\V7\"+ИмяПользователя()+"\Moxel\";
Сообщить(Ключ);
key = Registry.CurrentUser.OpenSubKey(Ключ);
ОсновнойКлюч=СокрЛП(key.Name)+"\";

Ключи=key.GetSubKeyNames();


 Перечислимый=Врап.ПолучитьИнтерфейс(Ключи,"IEnumerable");
 Перечислитель=Перечислимый.GetEnumerator();
// На всякий случай приведем к Интерфейсу IEnumerator

 Перечислитель=Врап.ПолучитьИнтерфейс(Перечислитель,"IEnumerator");
// Теперь можем пройтись по коллекции

 
Пока Перечислитель.MoveNext()<>0 Цикл
//  Врап.ВСтроку вывоит строковое представление всех типов в том числе числовые, строки, неопределено

    Сообщить(Врап.ВСтроку(Перечислитель.Current));

    Ключ=ОсновнойКлюч+СокрЛП(Перечислитель.Current);
    ТекПринтер=Registry.GetValue(Ключ,"DefaultPrinter","");
    Сообщить(ТекПринтер);
    
    Если (Принтер<>"") и (ТекПринтер<>"") и (Принтер<>ТекПринтер) Тогда

        Registry.SetValue(Ключ,"DefaultPrinter",Принтер);
    КонецЕсли;
КонецЦикла;
...Показать Скрыть
43. olo lo (olo_lo4) 23.04.16 20:01 Сейчас в теме
Добрый день.
врап=новый COMОбъект("NetObjectToIDispatch45");

1С-ка пишет
Ошибка при вызове конструктора (COMОбъект)
врап=новый COMОбъект("NetObjectToIDispatch45");
по причине:
-2147221005(0x800401F3): Недопустимая строка с указанием класса

какие библиотеки нужно доустановить? спасибо
45. olo lo (olo_lo4) 23.04.16 20:32 Сейчас в теме
(44) не получается. можно для тех кто в бронепоезде черным по белому написать.спасибо
46. Сергей Смирнов (Serginio) 499 23.04.16 21:18 Сейчас в теме
Вторая ссылка в шапке все написано
47. olo lo (olo_lo4) 23.04.16 21:25 Сейчас в теме
Для таких же как и я в подвоной лодке, для начала работы, скачиваете и распаковываете файл ФайлыNetObjectToIDispatch
далее в папке DLLNetObjetToIDispatch45 запускаем RegAsm.bat
либо из корня скаченного файла запускаем РегистрацияКомСервера.exe и выбираем NetObjetToIDispatch45.dll которая лежит в DLLNetObjetToIDispatch45

Взгляд со стороны, без обид:
у автора очень интересный и нужный контент, но подача просто швахт, разбираться в этом адском количестве ссылок и каше неразложенной инфы ...
48. Сергей Смирнов (Serginio) 499 23.04.16 21:38 Сейчас в теме
(47) В пианиста просим не стрелять - он играет как умеет.
49. Толик (user650124_dao-piglet) 09.12.16 18:34 Сейчас в теме
Сергей Смирнов, спасибо! Библиотека очень полезная, и у меня почти работает)))
Объекты HttpClient и HttpRequestMessage создаются.
А дальше нужно добавить к запросу Method и RequestUri - это не получается.
(В C# аналогичный код работает)

ХТТПЗапрос.RequestUri = Врап.СоздатьОбъект("System.Uri", адрес);
HttpMethod = Врап.ПолучитьТипИзСборки("System.Net.Http.HttpMethod", "System.Net.Http.dll");
ХТТПЗапрос.Method = HttpMethod.Get;

И в 1-й и в 2-й строках одинаковая ошибка:
Произошла исключительная ситуация (mscorlib): Exception has been thrown by the target of an invocation.

Получение System.Uri видел у Вас здесь и в других публикациях, скопировал. HttpMethod попробовал методом тыка.
Что я делаю не так? Заранее спасибо!

50. Сергей Смирнов (Serginio) 499 10.12.16 18:48 Сейчас в теме
Ты бы показал весь код на C#/ .

Например для WebRequest RequestUri только для чтения.

WebRequest=Врап.ПолучитьТипИзСборки("System.Net.WebRequest","System.dll");
	myWebRequest=WebRequest.Create("https://msdn.microsoft.com/en-us/library/system.net.webrequest.requesturi(v=vs.110).aspx");
    Сообщить("RequestUri "+myWebRequest.RequestUri.ToString());
	HttpMethod = Врап.ПолучитьТипИзСборки("System.Net.Http.HttpMethod", "System.Net.Http.dll");
	Сообщить(Врап.Встроку(HttpMethod));
...Показать Скрыть


Посмотри примеры Как вызвать метод из C# в 1С?

Там последние версии компонент и куча примеров. .Net Framework 4.6.1
51. Евгений Абдуразаков (asdfgcom) 60 12.12.16 21:18 Сейчас в теме
Пытаюсь подключить dll, не являющуюся COM-видимой.

{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(13)}: Ошибка при вызове метода контекста (ПолучитьТипИзСборки)
Infrascturcture=Врап.ПолучитьТипИзСборки("ZGuard.ZG_CTR_EV_TYPE","C:\SDK Guard\ZGuard.dll");
по причине:
Произошла исключительная ситуация (mscorlib): Не удалось загрузить файл или сборку "file:///C:\SDK Guard\ZGuard.dll" либо одну из их зависимостей. Ожидалось, что модуль содержит манифест сборки.

Понимаю, что она не является NET-сборкой. Можно ли это исправить, если есть исходник на C#?
Следует оговориться, что C# не владею (((
52. Сергей Смирнов (Serginio) 499 13.12.16 11:14 Сейчас в теме
53. иван лопатин (ivan811) 13.12.16 11:17 Сейчас в теме
Очень интересно!
Расширяет возможности интеграции
54. Сергей Смирнов (Serginio) 499 13.12.16 11:39 Сейчас в теме
55. Евгений Абдуразаков (asdfgcom) 60 13.12.16 16:36 Сейчас в теме
(52) Верно, Сергей. Главное, удалось, все-таки, перекомпилировать dll, после чего dll стала NET сборкой. Удалось достучаться до типов внутри. Сегодня попрактикуюсь вечером. Может и до контроллера достучусь.
Заслуженная звезда.
56. Евгений Абдуразаков (asdfgcom) 60 13.12.16 18:13 Сейчас в теме
Вот вопрос...
Код Dll:

namespace ZGuard
{
.......
 class ZGIntf
    {
.........
        public static int ZG_SearchDevices(ref IntPtr pHandle, ref ZP_SEARCH_PARAMS pParams, bool fSerial=true, bool fIP=true)
        {
            if (fSerial)
                pParams.nDevMask |= ZG_DEVTYPE_CVTS;
            if (fIP)
                pParams.nIpDevMask |= ZG_IPDEVTYPE_CVTS;
            return ZPIntf.ZP_SearchDevices(ref pHandle, ref pParams);
        }
.....................
...Показать Скрыть


т.е. вызов будет выглядеть как:
	врап=новый COMОбъект("NetObjectToIDispatch45");
	ZGIntf=Врап.ПолучитьТипИзСборки("ZGuard.ZGIntf","D:\КонфигурацииКлиентов\Импульс\ZGuard.dll");
	
	ZGIntf_Object=Врап.СоздатьОбъект(ZGIntf);
    IntPtr = Врап.ПолучитьТип("System.IntPtr");
    m_hCvt = IntPtr.Zero;
	Result = ZGIntf_Object.ZG_SearchDevices(); //пока не передаю параметров, т.к. не вижу метода	
...Показать Скрыть


получаю Метод объекта не обнаружен (ZG_SearchDevices)
не понял, как добраться до методов??? Вроде он объявлен public.
57. Сергей Смирнов (Serginio) 499 13.12.16 19:53 Сейчас в теме
А точно ZG_SearchDevices это метод объекта?
Может это статический метод?
Нужно обязательно передавать параметры, так как из-за перегрузок метод ищется по количеству и типам параметров
58. Сергей Смирнов (Serginio) 499 13.12.16 19:54 Сейчас в теме
59. Сергей Смирнов (Serginio) 499 13.12.16 20:01 Сейчас в теме
public static  int ZG_SearchDevices
Это метод класса (ключевое слово static). То есть нужно согласно объявлению

public static int ZG_SearchDevices(ref IntPtr pHandle, ref ZP_SEARCH_PARAMS pParams, bool fSerial=true, bool fIP=true)


вызвать



IntPtr = Врап.ПолучитьТип("System.IntPtr");
    m_hCvt = IntPtr.Zero;
    Result = ZGIntf.ZG_SearchDevices(m_hCvt,pParams,истина, истина); //пока не передаю параметров, т.к. не вижу метода    


ZG_SearchDevices(ref IntPtr pHandle, ref ZP_SEARCH_PARAMS pParams, bool fSerial=true, bool fIP=true)
...Показать Скрыть
60. Евгений Абдуразаков (asdfgcom) 60 13.12.16 20:16 Сейчас в теме
pParams - непонятно. Вообще, в этом месте предполагается callBack функция, возвращающая найденные контроллеры.
Вот пример кода на C#, обращающийся к данной функции:
      static bool EnumCtrsCB(ref ZG_FIND_CTR_INFO pInfo, int nPos, int nMax, IntPtr pUserData)
        {
            Console.WriteLine("{0}, адрес: {1}, с/н: {2}, v{3}.{4}, кл.: {5}, соб.: {6}, {7};",
                CtrTypeStrs[(int)pInfo.nType],
                pInfo.nAddr,
                pInfo.nSn,
                pInfo.nVersion & 0xff, (pInfo.nVersion >> 8) & 0xff,
                pInfo.nMaxKeys,
                pInfo.nMaxEvents,
                KeyModeStrs[((pInfo.nFlags & ZGIntf.ZG_CTR_F_PROXIMITY) != 0) ? 1 : 0]);
            g_nCtrCount++;
            return true;
        }

        static void DoGuardFindCtrs()
        {
            int hr;

            Console.WriteLine("Поиск контроллеров...");
            Console.WriteLine("-------------");
            g_nCtrCount = 0;
            hr = ZGIntf.ZG_Cvt_EnumControllers(m_hCvt, EnumCtrsCB, IntPtr.Zero);
            if (hr < 0)
            {
                Console.WriteLine("Ошибка ZG_Cvt_EnumControllers ({0}).", hr);
                Console.ReadLine();
                return;
            }
            if (g_nCtrCount > 0)
            {
                Console.WriteLine("-------------");
                Console.WriteLine("Найдено {0} контроллеров.", g_nCtrCount);
            }
            else
                Console.WriteLine("Контроллеры не найдены.");
        }

...Показать Скрыть
62. Евгений Абдуразаков (asdfgcom) 60 13.12.16 20:23 Сейчас в теме
Вообще, до конца неясно с dll. Дома стоит VC, попробую внимательно проверить и пересобрать библиотеку.
Попытка зарегистрировать DLL вываливается в ненайденную точку входа.
Кроме того обращение к функции инициализации библиотеки без параметров:

вв = ZGIntf.ZG_GetVersion();//она единственная без параметров точно


вываливается с ошибкой "Адресат вызова вызвал исключение.mscorelib System.EntryPointNotFoundException
63. Евгений Абдуразаков (asdfgcom) 60 13.12.16 20:25 Сейчас в теме
Вот-вот... С обертками я как раз и слаб пока))) Только-только типы научился брать.
64. Сергей Смирнов (Serginio) 499 13.12.16 20:25 Сейчас в теме
Либо при запуске формировать в некий список и из него уже выбирать контроллеры.
65. Сергей Смирнов (Serginio) 499 13.12.16 20:28 Сейчас в теме
Её не надо регистрировать. NetObjectToIDispatch45 как раз оборачивает .Net объекты через COM класс.

Для начала запусти примеры на C#. Потом двигайся к 1С.
66. Евгений Абдуразаков (asdfgcom) 60 13.12.16 20:29 Сейчас в теме
т.е. на стороне DLL предложить уже найденные контроллеры?
67. Евгений Абдуразаков (asdfgcom) 60 13.12.16 20:31 Сейчас в теме
(64) предположим, создать свою функцию в DLL, обращение к которой, с серийным номером контроллера выполнит его поиск и даст его HANDLE ?
Тем более есть рабочий пример такой функции на C#
68. Сергей Смирнов (Serginio) 499 13.12.16 20:38 Сейчас в теме
А System.EntryPointNotFoundException говорит о том, что не нашла она в нативной DLL метод ZG_GetVersion

https://msdn.microsoft.com/ru-ru/library/system.entrypointnotfoundexception(v=vs.110).aspx
69. Сергей Смирнов (Serginio) 499 13.12.16 21:25 Сейчас в теме
(67) Лучше дописать библиотеку под свои нужды.