Вход | Регистрация
    1  2  3

Пишу COM-ВК для 1C на С#

Пишу COM-ВК для 1C на С#
Я
   Гений 1С
 
23.12.20 - 14:11
Возникло пару вопросов к уважаемому ALL по материалам ветки: Собираюсь писать ВК для 1С на C#

Почему то при обращении COM-объекта к DLL-библиотеке ANVIZ NET ожидает встретить 32 или 64-разрядную dll библиотеку tc-b_new_sdk.dll в папке рядом
с моей компонентой AnvizCCH.dll.
Иначе пишет, что попытка запустить плохой файл.
Как сделать универсально, чтобы в зависимости от системы запускался тот или иной файл DLL.
AnvizCCH.dll зарегистрировал через regasm и для 32 и для 64.

В C# коде связывание tc-b_new_sdk.dll по имени tc-b_new_sdk
Я пока вижу только переименовать в tc-b_new_sdk32 и tc-b_new_sdk64 и сделать два проекта для 32 и 64 разрядных ОС. Но это как-то криво.
Можно проще как-то?

P.s: и как убрать мигающую елку справа, закрывает окно написания поста?
   Кирпич
 
201 - 08.01.21 - 22:04
(200) Это фигня. Я сейчас нашлепал всяких настроек в проект. Хелловорд в 13 мб получился. Вполне прилично по нашим временам. Экзешник в 6 мб и 4 dll столько же. Так что переходим на C#
   Кирпич
 
202 - 08.01.21 - 22:07
правда микрософт предупреждает что может и глюкануть
   Кирпич
 
203 - 08.01.21 - 22:08
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <RootNamespace>_12</RootNamespace>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
    <PublishReadyToRun>true</PublishReadyToRun>
    <PublishSingleFile>true</PublishSingleFile>
    <PublishTrimmed>true</PublishTrimmed>
    <TrimMode>link</TrimMode>
  </PropertyGroup>

</Project>
   Гений 1С
 
204 - 08.01.21 - 22:12
(200) да ну его в пень, скопипащу
   Serginio1
 
205 - 08.01.21 - 22:28
(203) Ну да автономное обрезанное приложение https://docs.microsoft.com/ru-ru/dotnet/core/deploying/trim-self-contained
Сам еще не пробовал. Но для доккеров очень удобно.
Рад, что ты все таки решился!
(204) Правильно самый простой и надежный путь!
   Serginio1
 
206 - 08.01.21 - 22:31
(202) Если у тебя нет Reflection то проблем не будет. Та же проблема и для .Net Native
Но можно указать сборки которые не стоит обрезать из за отображения
   Ненавижу 1С
 
207 - 08.01.21 - 22:46
(204) никто не сомневался в твоём выборе
   Гений 1С
 
208 - 13.01.21 - 07:04
Решил на досуге разобраться с 32/64.
Есть вариант сделать два проекта AnvizCCH32 и AnvizCCH64, отличающиеся только классом, описывающим DLL - линкующимся файлом "tc-b_new_sdk32.dll" и "tc-b_new_sdk64.dll" соответственно

Потому что попробовал так:

     public AnvizCCH() {
            [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
            static extern bool SetDllDirectory(string path);

            var basePath = Environment.CurrentDirectory;//AppDomain.Current.BaseDirectory;

            if (IntPtr.Size != 4)
                //if (Environment.Is64BitProcess)

                SetDllDirectory(Path.Combine(basePath, "x64"));
            else
                SetDllDirectory(Path.Combine(basePath, "x86"));

Пишет ошибку:


Ошибка    CS8370    Компонент "статические локальные функции" недоступен в C# 7.3. Используйте версию языка 8.0 или выше.    

ЧЯДНТ?
   Гений 1С
 
209 - 13.01.21 - 07:24
Хотя нет, вроде вышло:

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        static extern bool SetDllDirectory(string path);


       public AnvizCCH() {

            string basePath = Environment.CurrentDirectory//AppDomain.Current.BaseDirectory;


            if (IntPtr.Size != 4)
                //if (Environment.Is64BitProcess)


                SetDllDirectory(Path.Combine(basePath, "x64"));
            else
                SetDllDirectory(Path.Combine(basePath, "x32"));

Надо потестить, работает или нет на другом компе.
   Гений 1С
 
210 - 13.01.21 - 07:45
гм, проверил, работает.
Реально, если убрать каталог x64, то выдает ошибку, что не видит DLL, круто, че, спасибо Сергиньо
   Serginio1
 
211 - 13.01.21 - 10:39
Тебе проще использовать LoadLibrary.
Для исключения сайд эффектов

static class MyDll
{
    static AnvizCCH()
    {            
       var myPath = new Uri(typeof(AnvizCCH).Assembly.CodeBase).LocalPath;
        var myFolder = Path.GetDirectoryName(myPath);

        var is64 = IntPtr.Size == 8;
        var subfolder = is64 ? "x64" : "x32";

        LoadLibrary(Path.Combine(myFolder,subfolder ,"tc-b_new_sdk.dll");
    }

    [DllImport("kernel32.dll")]
    private static extern IntPtr LoadLibrary(string dllToLoad);

  
}
   Гений 1С
 
212 - 13.01.21 - 12:36
Получилось написать с разными типами параметров:

        public object SetParam(string param, object value = null)
        {
            object prev;
            prev = value;

            //Type currType = value.GetType();

            //AddLog("Param type: " + currType);

            

            if (value!= null)
                switch (param)
                {
                    case "GetUsersCount":
                        _GetUsersCount = Convert.ToInt64(value);
                        AddLog("Set param to: " + _GetUsersCount);
                        break;
                    case "UseLongName":
                        _UseLongName = Convert.ToBoolean(value);;
                        AddLog("Set param to: " + _UseLongName);
                        break;
                }
            return prev;
        }


Вот как вызываю из 1С:
    Компонента.SetParam("GetUsersCount", 1);    
    Компонента.SetParam("UseLongName", true);    
    Компонента.SetParam("UseLongName");
   Гений 1С
 
213 - 13.01.21 - 13:06
(211) спасибо, так и сделал, а что такое "сайд эффекты"?
   Serginio1
 
214 - 13.01.21 - 15:11
Ну у тебя может не только эта библиотека в 1С загружаться но и другие.
"Функция SetDllDirectory добавляет каталог к пути поиска, используемому, чтобы определить местонахождение DLL для прикладной программы."
И другие сборки могут и там искать
   Serginio1
 
215 - 13.01.21 - 19:18
А зачем такие сложности?

Сделай свойства GetUsersCount, UseLongName,UseLongName

public int GetUsersCount{
 get{
 return _GetUsersCount;
}
set{
 _GetUsersCount = value;
AddLog("Set param to: " + _GetUsersCount);

}
}
   Гений 1С
 
216 - 13.01.21 - 19:27
(215) задача - совместимость с прошлыми версиями.
а в прошлой версии VB мне было западло на каждое свойство писать отдельный метод ВК 1С, там в трех местах прописывать надо было.
   Гений 1С
 
217 - 16.01.21 - 17:36
компонента близится к завершению. Остается доделать чтение отпечатков пальцев и по мелочам.

забавные фичи:

1. Я использовал в компоненте один метод из библиотеки Сканера UBIO, чтобы конвертить одинарные отпечатки в двойные. Счас пытаюсь отговорить заказчика этот метод поддерживать, иначе придется еще и SDK UBIO втаскивать, ну или писать конвертор на C#, но там структура не понятна.

2. Почему то без точки останова на этой строке в VC компонента не стартует, а из 1С стартует:

            anviz_handle = AnvizNew.CChex_Start();
   
3. Вот какой забавный код по конвертации Int 32[] в byte[] (конвертирую массив отпечатков):

FP2 = convert_objectint32array_to_byte_array(user[7]);


     private byte[] convert_objectint32array_to_byte_array(object _objs)
        {
        
            Int32[] ints = (Int32[]) _objs;

            byte[] bytes = new byte[ints.Length];
            for (int i = 0; i < bytes.Length; i++)
                bytes[i] = (byte)ints[i];
            return bytes;

        }


4. Я как считывал на бейсике персоны? Сначала считываю очередную персону и тут же считываю ее отпечатки. В аснихроне так не прокатило.
Потому что как только я сделал запрос на персоны, в очереди 20 событий (на 20 персон ответ).
А я тут делаю после чтения 1 события запрос на отпечатки и оно помещается в конец очереди.
Приходится сначала считать персоны, а потом по каждой считывать отпечатки. Сперва не мог понять, что не так.
   Ненавижу 1С
 
218 - 16.01.21 - 18:10
(217) п.3: познай силу LINQ падаван )))

static private byte[] int32array_to_bytearray(object obj) => ((int[])obj).Select(i => (byte)i).ToArray();
   Serginio1
 
219 - 16.01.21 - 18:19
(217) покажи свой код с async.
Используй Wait или Result. Либо запихивай в очередь и обрашивай с переодичностью, раз от ВК отказался.
Или попробуй мой вариант
.NET(C#) для 1С. Динамическая компиляция класса обертки для использования .Net событий в 1С через ДобавитьОбработчик или ОбработкаВнешнегоСобытия
http://catalog.mista.ru/1c/articles/417830/
   Serginio1
 
220 - 16.01.21 - 18:20
Но на сервере тебе нет событий. Только опрос.
https://docs.microsoft.com/ru-ru/dotnet/api/system.collections.concurrent.concurrentqueue-1?view=net-5.0
   Гений 1С
 
221 - 16.01.21 - 18:21
Кстати, забавно, в прошлых версиях SDK личности назывались Person (что более правильно), а сейчас Employee.
И забавные опечатки в названиях методов, не Convert, а Converr. Гыгыгы
   Гений 1С
 
222 - 16.01.21 - 18:21
(218) у меня так в VC не сработало. Я пробовал
   Гений 1С
 
223 - 16.01.21 - 18:23
(219) у меня нет Asynk, я тупо опрашиваю очередь на ожидаемое событие. Ну вот например WaitUpdate тупо ждет по таймауту нужное событие:

            ret = AnvizNew.CCHex_ClientConnect(Handle(), System.Text.Encoding.Default.GetBytes(IP), port);
            AddLog("Result of Connect: " + ret);
            if (ret != 1) return false;

            //clear chain

            if (!WaitUpdate((int)AnvizNew.MsgType.CCHEX_RET_DEV_LOGIN_TYPE)) return false;

            AnvizNew.CCHEX_RET_DEV_LOGIN_STRU dev_info;
            dev_info = (AnvizNew.CCHEX_RET_DEV_LOGIN_STRU)Marshal.PtrToStructure(pBuff, typeof(AnvizNew.CCHEX_RET_DEV_LOGIN_STRU));
            log = log + "Dev Login --- MachineId:" + dev_info.MachineId + "\r\n"
                + " DevIdx:" + dev_info.DevIdx.ToString() + "\r\n"
                + " Version:" + byte_to_string(dev_info.Version) + "\r\n"
                + " DevType:" + byte_to_string(dev_info.DevType) + "\r\n"
                + " Addr:" + byte_to_string(dev_info.Addr) + "\r\n"
                + " Dev Type Flag:" + Convert.ToString(dev_info.DevTypeFlag, 16) + "\r\n";
            dev_id = dev_info.DevIdx;//remember dev_id

            dev_type_flag = dev_info.DevTypeFlag;
   Ненавижу 1С
 
224 - 16.01.21 - 18:23
(222) потому что это надо уметь:

using System.Linq;
   Гений 1С
 
225 - 16.01.21 - 18:23
»
   Гений 1С
 
226 - 16.01.21 - 18:24
(224) все так просто? ;-) По моему у меня Linq не подключается, но буду иметь ввиду
   Ненавижу 1С
 
227 - 16.01.21 - 18:25
(225) null, null, null - где-то такое уже было...
   Гений 1С
 
228 - 16.01.21 - 18:29
(227) я знал, что ты вспомнишь.
   Ненавижу 1С
 
229 - 16.01.21 - 19:17
(226) нет, если все так просто - то это значит, что ты не пробовал через LINQ - не надо врать
   Гений 1С
 
230 - 16.01.21 - 19:37
(229) я надыбал пример с селектом в интернетах, но он не взлетел, т.к. не находил метод Select у массива.
 
 Рекламное место пустует
   Ненавижу 1С
 
231 - 16.01.21 - 19:40
(230) понятно как ты теперь "умеешь программировать"  на C#
ты всегда так тыкаешь все подряд не осознавая что к чему?
   Гений 1С
 
232 - 16.01.21 - 19:43
(231) не знаю, всегда или нет. Но целей своих я добиваюсь.
   Гений 1С
 
233 - 16.01.21 - 19:57
Кстати, компоненту написал в черновом варианте. Там еще подполировать кой-чего надо будет.
Пойду посчитаю время, затраченное на нее. Чую овербюджет.
В Пн буду заказчику сдавать, думается.
   Волшебник
 
234 - 17.01.21 - 10:39
(233) Решил вопрос с имущественными правами? Кому будет принадлежать компонента?
   Гений 1С
 
235 - 17.01.21 - 10:45
(234) волшебник, а проблемы метеоритной угрозы меня тоже должны волновать? ггг... с правами вроде там не возникало споров.
   Кирпич
 
236 - 17.01.21 - 10:46
(233) Бери денег больше. Компенсировать месяц позора на мисте и унизительное чтение документации.
   Гений 1С
 
237 - 17.01.21 - 10:49
(236) я думаю, я ее еще несколько раз продам, не дорого, правда, но норм. Ради одной оказии писать бы не стал.
   Ненавижу 1С
 
238 - 17.01.21 - 11:02
В итоге одна компонента или две под 32 и 64?
   Гений 1С
 
239 - 17.01.21 - 11:09
(238) ты плохо следил за веткой. Одна ВК, она динамически при старте подгружает DLL из двух разных папок.
   Ненавижу 1С
 
240 - 17.01.21 - 11:12
(239) так себе сериал чтобы все подряд смотреть
   Гений 1С
 
241 - 18.01.21 - 12:42
Подскажите, а на C# есть готовая библиотека для криптографии опен-key.
ну есть открытый ключ, закрытый ключ и нужно проверить их соответствие.
в прошлой компоненте я это на VBasic писал
   Serginio1
 
242 - 18.01.21 - 13:18
   Serginio1
 
243 - 18.01.21 - 13:23
   Serginio1
 
244 - 18.01.21 - 13:34
   Serginio1
 
245 - 18.01.21 - 13:39
   Гений 1С
 
246 - 18.01.21 - 13:46
(242) эта ссылка не та, через COM-объект, остальные уже получше, хорошо
   Serginio1
 
247 - 18.01.21 - 14:21
(246) Суть не про Com объект, а про проверку сертификата.
Проверить соответствие открытого и закрытого ключа можно только закодировав массив байтов и разкодировать и сравнить.
В 245 старый пример. Смотри
https://docs.microsoft.com/ru-ru/dotnet/api/system.security.cryptography.cspparameters?view=net-5.0
https://docs.microsoft.com/ru-ru/dotnet/api/system.security.cryptography.rsacryptoserviceprovider.exportcspblob?view=net-5.0

или
https://docs.microsoft.com/ru-ru/dotnet/api/system.security.cryptography.rsacryptoserviceprovider.exportparameters?view=net-5.0
   Serginio1
 
248 - 18.01.21 - 14:29
Если у тебя ключи сохранены в Xml
https://gist.github.com/Jargon64/5b172c452827e15b21882f1d76a94be4/
   Гений 1С
 
249 - 21.01.21 - 09:34
Возник вопрос - как полностью уничтожить COM-объект, так, как это происходит при перезапуске 1С.
Может у COM есть какой-то метод.
COM = 0 не прокатывает, он все равно висит в памяти.
   Кирпич
 
250 - 21.01.21 - 09:50
(249) Зато в С# есть linq
   Ненавижу 1С
 
251 - 21.01.21 - 10:50
(249) на стороне 1С, на стороне dll?
   Serginio1
 
252 - 21.01.21 - 12:34
(249) Нетовские Com dll не выгружаются из памяти. То есть если у тебя есть статические переменные на которых есть ссылка на объект то они будут висеть в памяти.
Делай IDisposable
https://docs.microsoft.com/ru-ru/dotnet/standard/garbage-collection/implementing-dispose
И очищай ссылки в статичеких переменных в Dispose. Заодно можешь посмотреть когда срабатывает
   Serginio1
 
253 - 21.01.21 - 14:13
252 Да и висеть он может долго, пока сборка мусора не выполнится.
Ну и Кроме IDisposable и финализатора позоботься о закрытии портов сам в коде напрямую, а не надеяться на финализатор
https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/classes-and-structs/destructors
   Гений 1С
 
254 - 21.01.21 - 20:31
Что-то деструктор COM-Объекта не срабатывает автоматом при обнулении COM-Объекта.
Соответственно, не могу явно вызывать Stop, приходится это из 1С вызывать.
А если без Stop повторно создать AddIn.AnvizCCH, то не стартует CCH_Start, потому что она еще висит в памяти.
Это как-то лечится?
Пока советую создавать "AddIn.AnvizCCH" только раз и хранить на клиенте в гл.модуле.


Приходится писать код с явным вызовом Stop:

КомКомпонента = Новый COMОбъект("AddIn.AnvizCCH");

Порт                    = "1.1.4.6";
id                            = 0;//согласно описанию он не используется, всегда равен нулю

ПортАдреса    = 5010;

КомКомпонента.Debug(истина);

Для й = 1 По 2 Цикл
                Сообщить("=== Прогон: " + й);
                Результат = КомКомпонента.ConnectNet(Порт, id, ПортАдреса);
                Сообщить("  Результат подключения: " + Результат);
                Если Результат Тогда
                               Результат = КомКомпонента.GetDeviceClock();
                               Сообщить("  Время: " + Результат);
                               Результат = КомКомпонента.Close(id);
                               Сообщить("  Результат закрытия: " + Результат);
                КонецЕсли;
КонецЦикла;

КомКомпонента.Stop();

Сообщить(КомКомпонента.Debug());
   Serginio1
 
255 - 21.01.21 - 20:39
(256) Ну он не сработает пока сборка мусора не вызовется. Сделай еще ком объект который и будет вызывать сборку мусора.
Почитай мои статьи.
GC.Collect();
// Waiting till finilizer thread will call all finalizers

GC.WaitForPendingFinalizers();
   Гений 1С
 
256 - 21.01.21 - 20:43
(255) Пробую, но как-то сложно дается тема реализации интерфейсов в своем классе.
   Serginio1
 
257 - 21.01.21 - 20:53
(256) Но в любом случае лучше самому вызывать закрытие ресурсов перед обнулением ссылки на Com объект.
GC.Collect();
GC.WaitForPendingFinalizers();

 это подчистка твоих огрехов.

Интерфейсы это просто. По сути пишешь те же методы и свойства только публичные и с реализацией. Ничего сложного нет.
Просто финализаторы вызываются после сборки мусора,а IDisposable можешь вызвать хоть откуда.
Но при финализации нужно учесть, что объект уже закрыт, поэтому при закрытии нужно еще убрать объект из очереди финализаторов и для объекта вызвать
GC.SuppressFinalize(Object)
https://docs.microsoft.com/ru-RU/dotnet/api/system.gc.suppressfinalize?view=net-5.0

Есть куча паттернов
  1  2  3

Список тем форума
Рекламное место пустует  Рекламное место пустует
ВНИМАНИЕ! Если вы потеряли окно ввода сообщения, нажмите Ctrl-F5 или Ctrl-R или кнопку "Обновить" в браузере.