Неправильная сигнатура взаимодействия, приводящая к утечке памяти - PullRequest
1 голос
/ 14 апреля 2011

Сторонний com-модуль, используемый из c # через интерфейс, сгенерированный взаимодействием, вызывает утечку памяти

Сторонняя сигнатура метода c ++:

somemethod(....., long** param3, long** param4)

Сгенерированный метод взаимодействия:

somemethod(...., IntPtr param3, IntPtr param4)

Последние 2 параметра присваиваются массивами неуправляемой dll и освобождаются от c # Marshal.CoMemFree (не помню точный sig atm)

Используя тот же метод из C ++ через интерфейс com иосвобождение таким же образом не приводит к утечкам

Использование tlbimp из командной строки приводит к:

TlbImp : warning TI0000 : At least one of the arguments for
'Sometype.somemethod' cannot be marshaled by the runtime
marshaler. Such arguments will therefore be passed as a pointer and may
require unsafe code to manipulate.

Я нахожу удивительным, что длинные ** параметры не могут быть автоматически собраны.

Лучше понимать c ++ (кроме черной магии Com), чем .net, но реализовывать сторону .net ...

Как правильно получить доступ и освободить память, переданную обратно в param3 иparam4.Я подозреваю, что они должны быть вне IntPtr?

Ответы [ 2 ]

3 голосов
/ 14 апреля 2011

Это объявление полностью несовместимо с COM Automation.Массивы необходимо передавать как SAFEARRAY, чтобы было кристально ясно, насколько они велики и как управляется их память.Передача long ** означает , обычно , что означает, что вызываемый объект отвечает за выделение массива и возврат указателя на массив.Точно как это должно быть выделено, это проблема, не ясно, должен ли он использовать кучу процесса, кучу COM или может использовать кучу CRT.

Броски Tlbimp.exeподгонка, он не знает, как правильно перевести тип аргумента.Вам придется декомпилировать библиотеку взаимодействия с помощью ildasm.exe, отредактировать IL, чтобы превратить аргумент в выход IntPtr или int [], и снова скомпилировать его с помощью ilasm.exe.Единственное разумное предположение для распределителя - Marshal.AllocCoTaskMem ().Может работать, может плохо просачиваться.Вам нужна помощь поставщика или автора компонента, чтобы не догадываться.

0 голосов
/ 16 апреля 2011

Нашел «способ» получить ожидаемую функциональность, но не уверен, насколько обоснованным является решение.Следующие работы без утечек

long* arr1 = null;
long* arr2 = null;

IntPtr parr1 = new IntPtr(&arr1);
IntPtr parr2 = new IntPtr(&arr2);

somemethod(....., parr1, parr2);

Marshal.CoTaskMemFree(new IntPtr(arr1));
Marshal.CoTaskMemFree(new IntPtr(arr2));

Предостережения:

  1. Не пытались получить доступ к массивам, мне на самом деле не нужно содержимое, но я думаю, что для этоговероятно, требуются вызовы Marshall.Copy.

  2. Интуитивно, вызов должен быть каким-то способом (....., ref parr1, ref parr2);Однако кажется, что IntPtr на самом деле больше похож на пустой указатель, поэтому, хотя он передается по значению, его значение является адресом arr1, поэтому вызываемый абонент может назначить в arr1, пахнет неправильно, но это работает, возможно, arr1 или parr1 должны быть выделены с помощьюMarshal.CoTaskMemAlloc (?)

  3. Я пробовал описанное выше в консольном приложении, и оно все еще просачивалось, однако при указании [STAThread] (вместо того, чтобы не указывать / по умолчанию) утечкаостанавливается.Факт, что квартира вещь меняет смысл кода, так что тонкость воняет

...