|
Как выгрузить COM dll ? | ☑ | ||
---|---|---|---|---|
0
DES
20.11.15
✎
20:58
|
сделал на C# свою COM dll.
Загружаю на сервере 1С. Все работает. Но вот кажется dll создает проблему при загрузке *.dt. Так как система ругается что dll захвачена какой -то программой и ее заменить не удается, пока не перезагружу 1с-сервер. Т.е. при обращении клиента к серверу он грузит dll и захватывает ее файл и держит до скончания веков. Как отпустить файл dll в у конце процесса на сервере? |
|||
1
mehfk
20.11.15
✎
21:00
|
"ругается что dll захвачена какой -то программойЙ"
Скриншот покажи. |
|||
2
DES
20.11.15
✎
21:01
|
ну не вопрос какой программой, вопрос как освободить.
А ругается при загрузке *.dt winsock откинулся на стороне сервера. |
|||
3
ДенисЧ
20.11.15
✎
21:12
|
так и должно быть.
Расслабься и выпей коньяку. |
|||
4
DES
20.11.15
✎
21:19
|
ну неужели нельзя вернуть память в кучу ??
|
|||
5
Serginio1
20.11.15
✎
21:37
|
(4) О ты уже на C# программируешь. Быстро.
По сабжу то это не простая манагед память, а скомпилированная нативная. Она не выгружается. Можно выгрузить только домен полностью, но это по сути отдельный процесс в едином адресном пространстве |
|||
6
su_mai
20.11.15
✎
21:57
|
(0) поставь process explorer и по имении dll найди программу её использующую.
https://technet.microsoft.com/ru-ru/sysinternals/processexplorer.aspx |
|||
7
su_mai
20.11.15
✎
21:59
|
(2) Какой то поток в dll работает, может TCPListener слушает порт или что то еще?
|
|||
8
Serginio1
20.11.15
✎
22:28
|
5+ DynamicMethod подвергается сборке мусора.
Кстати, то что DLL не выгружается есть и свои плюсы. Ты можешь в статических полях держать данные. По сути это аналог переменных на сервере правда только в одном рабочем процессе |
|||
9
DES
20.11.15
✎
22:34
|
(8) это все понятно, плохо то что не могу загрузить данные с рабочей базы в тестовую на том же сервере. Нужно перезапустить процесс 1С, а это не всегда возможно. А как перезагрузить сервер 1с для конкретного инстанса ?
|
|||
10
DES
20.11.15
✎
22:36
|
(2) Да, работаю с winsock , но вроде бы закрываю канал сразу после чтения
|
|||
11
DES
20.11.15
✎
22:36
|
(10)->(7)
|
|||
12
H A D G E H O G s
20.11.15
✎
22:37
|
"в статических полях держать данные"
все равно указатель на клиент возвращать |
|||
13
DES
20.11.15
✎
22:38
|
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sender.Shutdown(SocketShutdown.Both); sender.Close(); |
|||
14
H A D G E H O G s
20.11.15
✎
22:42
|
(13) попробуй
FreeLibraryAndExitThread( HlNSTANCE hinstDll, DWORD dwExitCode); |
|||
15
H A D G E H O G s
20.11.15
✎
22:47
|
очень годная статья про dll
http://wm-help.net/books-online/print-page/59464/59464-14.html из нее я только что узнал про переадресацию |
|||
16
su_mai
20.11.15
✎
22:48
|
(11) Открой процесс dll в process explorer и посмотри в Threads и LAN что творится
|
|||
17
DES
20.11.15
✎
22:56
|
(5) кстати, могу выложить код сюда, чтобы маэстро оценил труды.
|
|||
18
Serginio1
20.11.15
✎
23:04
|
(17) Главное, что мои труды не пропали зря. Молодец.
|
|||
19
DES
20.11.15
✎
23:35
|
я, вообщем то, удивляюсь на этот код, но он работает, причем на сервере.
using System; using System.Text; using System.Runtime.InteropServices; using System.Net; using System.Net.Sockets; namespace Online { [Guid("13011962-0013-0001-1962-001301196200")] internal interface IMyClass { [DispId(1)] string Exec(string ConnectString, string CMD, string partXML, bool Otladka); } [Guid("70DD7E62-7D82-4301-993C-B7D919430992"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface IMyEvents { } [Guid("69EE0677-884A-4eeb-A3BD-D407844C0C72"), ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(typeof(IMyEvents))] public class Utilites : IMyClass { public string Exec(string LogPass, string CMD, string oXML, bool Otladka = false) { string Otvet = ""; string[] AllHERE; AllHERE = LogPass.Split(new char[] { ':', '@' }, 4); string myLog = AllHERE[0]; string myPass = AllHERE[1]; string IPaddr = AllHERE[2]; int IPport = Int32.Parse(AllHERE[3]); StringBuilder sb = new StringBuilder(); sb.Append("AUTH\0\0" + (char)(22) + "\0"); sb.Append((char)myLog.Length); foreach (char ch in myLog) sb.Append(ch); for (int i = myLog.Length; i < 10; i++) sb.Append(" "); sb.Append((char)myPass.Length); foreach (char ch in myPass) sb.Append(ch); for (int i = myPass.Length; i < 10; i++) sb.Append(" "); sb.Append("SEND\0\0"); string XML = ""; if (CMD == "ExecNature") XML = oXML; else XML = "<?xml version=\"1.0\" encoding=\"Windows-1251\"?><Request><RequestName>" + CMD + "</RequestName>" + oXML + "</Request>"; byte[] byteLen = BitConverter.GetBytes((UInt16)XML.Length); sb.Append((char)byteLen[0]); // тут режет старший бит, поэтому просто резервируем место sb.Append((char)byteLen[1]); foreach (char ch in XML) sb.Append(ch); string strXML = sb.ToString(); byte[] byteXML = Encoding.ASCII.GetBytes(strXML); byteXML[36] = byteLen[0]; // а тут перезаписываем длину XML правильно byteXML[37] = byteLen[1]; if (Otladka) Otvet = XML; else { try { IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(IPaddr), IPport); Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { byte[] bytes = new byte[0x1000]; sender.Connect(remoteEP); int bytesSent = sender.Send(byteXML); int bytesRec = sender.Receive(bytes); if (Encoding.ASCII.GetString(bytes, 0, 4) == "recv") { bytesRec = sender.Receive(bytes); byte[] AskByte = new byte[bytesRec]; System.Buffer.BlockCopy(bytes, 0, AskByte, 0, bytesRec); Otvet = Encoding.GetEncoding("Windows-1251").GetString(AskByte); } else { Otvet = "ERROR"; } } catch (ArgumentNullException ane) { Otvet = ane.ToString(); } try { sender.Shutdown(SocketShutdown.Both); sender.Close(); } finally {}; } catch (SocketException se) { Otvet = se.ToString(); } } return Otvet; } } } |
|||
20
DES
20.11.15
✎
23:39
|
все таки есть какой то метод выгрузки,
только куда его примастырить ? |
|||
21
Serginio1
20.11.15
✎
23:49
|
Так на будущее проще и моднее использовать WCF
|
|||
22
su_mai
21.11.15
✎
06:16
|
(19) Вызывает смущение:
try { sender.Shutdown(SocketShutdown.Both); sender.Close(); } finally {}; нет catch и finally пустой Вообще так не пишут используют конструкцию using(var obj = new MyClass) { трололо } https://msdn.microsoft.com/ru-ru/library/yh598w02.aspx |
|||
23
DES
21.11.15
✎
11:02
|
(22) как конкретно нужно бы ?
|
|||
24
su_mai
21.11.15
✎
11:37
|
может так
//Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); using(Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { try { byte[] bytes = new byte[0x1000]; sender.Connect(remoteEP); int bytesSent = sender.Send(byteXML); int bytesRec = sender.Receive(bytes); if (Encoding.ASCII.GetString(bytes, 0, 4) == "recv") { bytesRec = sender.Receive(bytes); byte[] AskByte = new byte[bytesRec]; System.Buffer.BlockCopy(bytes, 0, AskByte, 0, bytesRec); Otvet = Encoding.GetEncoding("Windows-1251").GetString(AskByte); } else { Otvet = "ERROR"; } } catch (ArgumentNullException ane) { Otvet = ane.ToString(); } sender.Shutdown(SocketShutdown.Both); sender.Close(); } |
|||
25
DES
21.11.15
✎
15:16
|
не понял
Убрать try с sender.Shutdown ? А если канал не открылся ? |
|||
26
su_mai
21.11.15
✎
17:08
|
(25) Нельзя маскировать исключение в фиктивном блоке try или Попытка, что в C#?, что в 1С. Ошибка может скрыться, а неуправляемые ресурсы повиснуть, подвесив сам объект в куче или хрен знает что еще.
|
|||
27
Serginio1
21.11.15
✎
17:34
|
(26) finally ничего не маскирует она нужна для очистки ресурсов перед вызовом исключения по стеку
https://msdn.microsoft.com/ru-ru/library/zwc8s4fz.aspx В его примере в его блок просто не нужен. В рамках обработки исключений, связанный блок finally гарантированно будет выполнен. Однако если исключения необработано, то выполнение блока finally зависит от того, как активирована операция очистки исключения. Это, в свою очередь, зависит от того, как настроен компьютер. Дополнительные сведения см. в статье Обработка необработанных исключений в CLR. |
|||
28
su_mai
21.11.15
✎
17:39
|
(27) Там внизу мелким шрифтом:
|
|||
29
su_mai
21.11.15
✎
17:39
|
(28) C# также содержит оператор using, который предоставляет аналогичную функциональность для объектов IDisposable в удобном синтаксисе.
|
|||
30
DES
21.11.15
✎
20:02
|
(26) а разве try не есть аналог транзакции ?
происходит откат всех действий, в том числе и удаление всех переменных ? |
|||
31
su_mai
21.11.15
✎
21:39
|
(30) Тема управления памятью CLR объемная, но хорошо описана.
Если упрощенно, то среда CLR выделяет память в "управляемой куче" для новых объектов оператором new. Когда на объект нет ссылок он признается подлежащим удалению и помещается в очередь удаления. Со временем уборщик мусора удалит его. Однако, если во время выполнения объект захватывал внешние неуправляемые CLR данные и не освободил их сам, то образуются утечки памяти. Например если создать временный файл на диске и не удалить его то объект удалиться, а файл останется. (Такое же поведение и в транзакциях.) Есть правило, если класс оперирует неуправляемыми данными, то он должен наследовать интерфейс IDisposable и соответственно реализовать метод Dispose(), в котором освободить все "хвосты". При использовании таких объектов необходимо учитывать, что выполнение программы может прерваться из-за исключения, по этому используют конструкцию <Создание объекта> try { <Использование объекта> } finally { <Вызов метода объекта Dispose> } Это громоздкая конструкция заменяется элегантной using(<Создание объекта>) { <Использование объекта> } Компилятор преобразует её в конструкцию try finally. |
|||
32
Serginio1
21.11.15
✎
22:50
|
(29) Я к (26), что finally ничего не маскирует
|
|||
33
su_mai
22.11.15
✎
14:49
|
(32) Да, оно просто не успевает, его процесс "убивают" раньше...
|
|||
34
Serginio1
22.11.15
✎
15:10
|
(33) Еще раз finally ничего не маскирует. Так же вызывается исключение. Просто если бы внутри finally закрывались ресурсы смысл в нем был бы. Плюс если бы по стеку в catch обрабатывалось исключение
|
|||
35
Serginio1
22.11.15
✎
15:13
|
(33) Кстати, а почему ты не используешь
http://catalog.mista.ru/profile/82159/public/ |
|||
36
su_mai
22.11.15
✎
15:23
|
(34) И я о том же, просто некорректно сказал про маскировку. Я хотел сказать, что создается видимость обработки исключения. Поэтому я и распинался про using.
(35) А должен? :) |
|||
37
Serginio1
22.11.15
✎
16:00
|
(36) finally не обрабатывает исключение
Так и расскажи почему тебя не заинтересовало. Например с http://catalog.mista.ru/public/238584/ можно отказаться от создания ВК. Особенно с динамической компиляцией обертки событий . Можешь получить глобальный контекст для вызова функций 1С, а так же получения интерфейсов IAsyncEvent,IExtWndsSupport итд. Кстати там обертка для глобального контекста, так как тип и объект при вызове if (args.Length == 1 && args[0].GetType() == typeof(System.Object[])) result = ТипГК.InvokeMember(binder.Name, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, App1C, (System.Object[])args[0]); else result = ТипГК.InvokeMember(binder.Name, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, App1C, args); Это не есть сущности одного объекта ТипГК = ГК1С.GetType(); App1C = ГК1С.AppDispatch; Там куча вещей которые можно использовать. |
|||
38
Serginio1
22.11.15
✎
16:07
|
Кстати про фильты искключений в C# 6
http://rsdn.ru/article/RSDN-2014-2/Docs/11-12-filters/11-12-filters.xml |
|||
39
su_mai
22.11.15
✎
16:09
|
(37) (38) Спасибо посмотрю на досуге!
|
|||
40
DES
23.11.15
✎
14:24
|
раз вы уже тут, то поясните про GUID-ы
ИХ там 3 шт, Какой в них смысл. Не один из них не нашел в реестре по-ходу после регистрации dll. |
|||
41
Serginio1
23.11.15
✎
15:07
|
ProgID поставь.У тебя же есть примеры.
[ComVisible(true)] [ProgId("NetObjectToIDispatch45")] [ClassInterface(ClassInterfaceType.AutoDispatch)] [Guid("DFDADA57-B22C-4276-928A-8B91C9891FF1")] public class NetObjectToIDispatch45 Тем более испорльзуя .NET(C#) для 1С. Динамическая компиляция класса обертки для использования .Net событий в 1С через ДобавитьОбработчик или ОбработкаВнешнегоСобытия Писать COM объект не нужно http://catalog.mista.ru/public/417830/ |
|||
42
Serginio1
23.11.15
✎
15:08
|
Или там можно сгенерировать как C# файлы, так и 1С методы событий
|
|||
43
Serginio1
23.11.15
✎
15:10
|
Если ты библиотеку подгружаешь через NetObjectToIDispatch45 то зачем тебе засорять регистр?
|
|||
44
DES
23.11.15
✎
16:47
|
нет, я гружу только свою ДЛЛ и она работает. (без оберток)
примеры то я взял, но что к чему не разобрался до конца. |
|||
45
Serginio1
23.11.15
✎
17:33
|
А как ты в 1С подключаешь?
|
|||
46
Serginio1
23.11.15
✎
17:40
|
А вообще тебе интерфейсы не нужны. Ты их не используешь.
Нужно только [ComVisible(true)] [ProgId("ИмяТвоегоКласса")] [ClassInterface(ClassInterfaceType.AutoDispatch)] [Guid("AFDADA57-B22C-4276-928A-8B91C9891FF1")] public class Utilites Тогда вызов из 1С объект=Новый ComОбъект("ИмяТвоегоКласса"); и все публичные методы и непомеченные как [ComVisible(false)] будут видны |
|||
47
xaozai
23.11.15
✎
18:03
|
Об = Новый COMОбъект("ТвойОбъект");
|
|||
48
DES
23.11.15
✎
20:41
|
(47) Об.ЗавершитьРаботуКомпонента()
а что в DDL в этой функуции ? |
|||
49
DES
23.11.15
✎
20:42
|
(46) это [Guid("AFDADA57-B22C-4276-928A-8B91C9891FF1")]
от фонаря или строго определенный ? |
|||
50
H A D G E H O G s
23.11.15
✎
20:46
|
(48) Ничего.
Это еротические фантазии автора (47). |
|||
51
H A D G E H O G s
23.11.15
✎
20:51
|
(49) Давай мы попробуем что-то придумать, если:
1) Ты можешь дать удаленный доступ 2) Есть сервер 1с в режиме отладки, который можно завалить. |
|||
52
DES
23.11.15
✎
22:38
|
(51) правда что ли ?
|
|||
53
DES
23.11.15
✎
22:40
|
(51) организуем завтра
|
|||
54
Serginio1
23.11.15
✎
23:35
|
(49) Гуид должен быть уникальным. В VS сервис- создать GUID
|
|||
55
DES
24.11.15
✎
00:14
|
(46)
Не догоняю, какие строчки лишние? У меня и так срабытывает объект=Новый ComОбъект("ИмяТвоегоКласса"); в частности объект=Новый ComОбъект("Online.Utilites"); |
|||
56
DES
24.11.15
✎
10:11
|
(51) переделал try на using
dll-ко стало вести себя прилично, т.е. не блокирует загрузку *.dt. Спасибо за желание помочь. |
|||
57
Serginio1
24.11.15
✎
10:36
|
(55) Тогда класс у тебя должен описан как в (46)
И соответсвенно ты должен найти Guid этого класса. В регистр записываются только GUID класса у которого определен ProgId. Кстати в моих примерах есть обмен по TCP/IP |
|||
58
DES
24.11.15
✎
10:48
|
(57) там у тебя асинхронный пример
|
|||
59
Serginio1
24.11.15
✎
11:05
|
(58) Нет отправка там синхронная
Функция СоздатьСерверTCP(Врап) Если не ЗначениеЗаполнено(ИмяФайлаСборки) Тогда // предупреждение("Не выбрано Имя Файла Сборки"); вызватьИсключение "Не выбрано Имя Файла Сборки" КонецЕсли; врап=новый COMОбъект("NetObjectToIDispatch45"); ФайлСборки=ИмяФайлаСборки;//"d:\MyPrograms\Test\ОбменПоTCPIP\ОбменПоTCPIP\bin\Debug\ОбменПоTCPIP.dll"; Сборка=врап.загрузитьСборку(ФайлСборки); //ПроектИспользованияДелегатов.dll тип=Сборка.GetType("TCPConnectTo1C.TCPConnector"); рез=врап.СоздатьОбъект(Тип); возврат рез КонецФункции // СоздатьTCP() Процедура ОтправитьКомандуНажатие(Элемент) перем Врап; КлиентTCP=СоздатьСерверTCP(Врап); ServerAdress="127.0.0.1"; порт=6891; Команда="Тест Отправки Сообщения"; ДанныеДляКоманды=XmlСтрока(ТекущаяДата()); ЕстьОтвет=истина; ЗакрытьСоединение=истина; ОшибкаСоединения=false; резулт=КлиентTCP.ОтправитьКоманду(ServerAdress,порт,Команда,ДанныеДляКоманды,ЕстьОтвет,ЗакрытьСоединение); Сообщить(резулт.Данные); Если резулт.ОшибкаСоединения Тогда СтрОшибки="ОшибкаСоединения |"+резулт.Данные; Предупреждение(СтрОшибки); КонецЕсли; КонецПроцедуры |
|||
60
Serginio1
24.11.15
✎
11:11
|
bool СоединитьсяССервером(string ServerAdress,int порт)
{ IPEndPoint ipEndpoint = new IPEndPoint(IPAddress.Parse(ServerAdress), порт); //6891 try { if (клиент == null) { клиент = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); клиент.Connect(ipEndpoint); } return true; } catch (SocketException ex) { MessageBox.Show("Ошибка соединения с сервером: " + ex.Message); клиент.Close(); клиент = null; return false; } } public ДанныеОтветаПоTCP ОтправитьКоманду(string ServerAdress,int порт,string Команда, string ДанныеДляКоманды, bool ЕстьОтвет, bool ЗакрытьСоединение) { bool ОшибкаСоединения=false; var result = ""; try { if (!СоединитьсяССервером(ServerAdress,порт)) { ОшибкаСоединения = true; return new ДанныеОтветаПоTCP("Ошибка", ОшибкаСоединения); } using (var strim = new NetworkStream(клиент)) { try { ДляОбменаПоТСП.ОтправитьКоманду(strim, Команда, ДанныеДляКоманды, ЕстьОтвет); if (ЕстьОтвет) result = ДляОбменаПоТСП.ReadCompressedString(strim); } catch (SocketException ex) { MessageBox.Show("Ошибка отправки данных: " + ex.Message); result = "Ошибка"; ОшибкаСоединения = true; } if (ЗакрытьСоединение) { клиент.Close(); клиент = null; } } } catch (SocketException ex) { MessageBox.Show("Ошибка соединения с сервером: " + ex.Message); result = "Ошибка"; ОшибкаСоединения = true; } var res = new ДанныеОтветаПоTCP(result, ОшибкаСоединения); return res; } } |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |