|
v7: Внешняя компонента COM на C# не выгружается | ☑ | ||
---|---|---|---|---|
0
Other
31.08.18
✎
13:50
|
Пишу компоненту, она реализует IInitDone и ILanguageExtender.
public void Init([MarshalAs(UnmanagedType.IDispatch)] object pConnection) { V7Data.V7Object = pConnection; } public void Done() { V7Data.V7Object = null; GC.Collect(); GC.WaitForPendingFinalizers(); } Пока я не трогаю указатель на IDipspath - всё прекрасно. Объект создается, при закрытии 1с вызывается метод Done(). Однако, стоит потрогать указатель и компонента из памяти больше не выгружается. Например: var obj1c = V7Data.V7Object.GetType().InvokeMember("AppDispatch", System.Reflection.BindingFlags.GetProperty, null, V7Data.V7Object, null); var obj = Marshal.GetIDispatchForObject(obj1c); int b = Marshal.Release(obj); Так вот, сколько бы раз я не вызывал Release(), число ссылок в b остается неизменным, т.е. Release() не уменьшает счетчик ссылок. Что я таки делаю не так? |
|||
1
H A D G E H O G s
31.08.18
✎
14:05
|
странный какой то у тебя done()
Вообще это функция, которая должна вернуть в 1С \ S_OK |
|||
2
H A D G E H O G s
31.08.18
✎
14:06
|
function AddInExtension.Done:HResult; stdcall;
// 1С вызывает эту функцию при завершении работы компоненты begin vk_object.Destroy(); iError:=nil; iEvent:=nil; Done:=S_OK; end; |
|||
3
Other
31.08.18
✎
14:07
|
(1) Если из функций IIinitDone в .net что-то возвращать - всё вообще валится в exception.
|
|||
4
Other
31.08.18
✎
14:08
|
За основу я брал код шаблона из RSDN.
|
|||
5
H A D G E H O G s
31.08.18
✎
14:09
|
(3) stdcall есть?
|
|||
6
H A D G E H O G s
31.08.18
✎
14:10
|
В done() хоть заходит?
|
|||
7
Other
31.08.18
✎
14:13
|
(6) Только начал писать. )) Если просто подключить компоненту и закрыть 1с - Done() вызывается. Если что-то сделать с указателем на IDispatch - не вызывается.
|
|||
8
H A D G E H O G s
31.08.18
✎
14:14
|
(7) А если так
var obj1c = V7Data.V7Object.GetType().InvokeMember("AppDispatch", System.Reflection.BindingFlags.GetProperty, null, V7Data.V7Object, null); var obj = Marshal.GetIDispatchForObject(obj1c); obj = null; obj1c = null; GC.Collect(); GC.WaitForPendingFinalizers(); |
|||
9
H A D G E H O G s
31.08.18
✎
14:15
|
Вернее
obj = null; obj1c = null; V7Data.V7Object = null; GC.Collect(); GC.WaitForPendingFinalizers(); |
|||
10
Other
31.08.18
✎
14:25
|
(9) var obj = Marshal.GetIDispatchForObject(obj1c);
Тип значения obj будет IntPtr. Он не принимает null. Тип obj1c будет COM callable wrapper и его обнуление ничего не дает, т.к. не уничтожается сам COM объект. Чтобы сборщик мусора освободил память, нужно счетчик ссылок именно на COM объект до нуля, если я правильно понял. Для этого есть метод Release() класса Marshal, но он почему-то не уменьшает счетчик ссылок. |
|||
11
Other
31.08.18
✎
14:27
|
Т.е. я получаю указатель IntPtr на ком объект, передаю его в метод Release, результатом выполнения метода будет число оставшихся ссылок на этот объект. Например 2. Я вызываю Release еще раз - результат всё равно 2.
|
|||
12
Other
31.08.18
✎
14:56
|
var obj = Marshal.GetIDispatchForObject(obj1c);
var obj1 = Marshal.GetIDispatchForObject(V7Data.V7Object); int a = Marshal.Release(obj); int b = Marshal.Release(obj1); while (a > 0 || b > 0) { a = Marshal.Release(obj1); b = Marshal.Release(obj1); } А вот так счетчики ссылок уменьшаются. Интересно... |
|||
13
Other
31.08.18
✎
18:32
|
В общем, заработало вот так:
public void Done() { if (_obj1c != null) { var obj1cPtr = Marshal.GetIDispatchForObject(_obj1c); int rc = Marshal.Release(obj1cPtr); while (rc > 0) { rc = Marshal.Release(obj1cPtr); } _obj1c = null; } if (_obj1c != null) { var connectionPtr = Marshal.GetIDispatchForObject(V7Data.V7Object); int rc = Marshal.Release(connectionPtr); while (rc > 0) { rc = Marshal.Release(connectionPtr); } V7Data.V7Object = null; } GC.Collect(); GC.WaitForPendingFinalizers(); } V7Object статическое свойство класса V7Data _obj1c вынес в приватное поле основного класса, реализующего IInitDone. Если нужно создавать объекты агрегатных типов - ссылки на них приходится хранить в глобальной коллекции, а потом в цикле освобождать Marshal.Release(). Как-то так |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |