Передайте массив ulong64 из VC ++ в VC # и освободите память - PullRequest
1 голос
/ 20 февраля 2012

Я вызываю метод из C # примерно так:

[DllImport(@"C:\Hash.dll",
    CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr ph_dct_videohash(
        string file,
        ref int length);


    static void Main(string[] args)
    {
            int length = 0;
            ph_dct_videohash(@"C:\Users\shady\H.avi", ref length);
            Console.Read();

    }

А вот метод, который я вызываю из библиотеки

ulong64* ph_dct_videohash(const char *filename, int &Length){

CImgList<uint8_t> *keyframes = ph_getKeyFramesFromVideo(filename);
if (keyframes == NULL)
    return NULL;

Length = keyframes->size();

ulong64 *hash = (ulong64*)malloc(sizeof(ulong64)*Length);
//some code to fill the hash array
return hash;}

Вопрос в том, как мне получить 64-битный массив без знака в C # и освободить память после его использования. Было бы еще лучше, если бы им управлял сборщик мусора для меня.

Я попробовал Marshal.copy, но это не сработало, и я боюсь, что будет утечка памяти (я не знаю, будет ли память освобождена автоматически или нет). Любая помощь будет оценена. Благодарю.

1 Ответ

2 голосов
/ 20 февраля 2012

У вас есть два способа следовать:

  1. Добавьте «свободную» функцию в вашу библиотеку и вызывайте ее явно для каждого ресурса, выделенного на стороне библиотеки. Это требует наименьшего количества изменений кода на стороне библиотеки, но вы должны помнить о освобождает память, если только вы не создадите IDisposable обертку для IntPtr, которая будет выполнять эту работу автоматически. Например, вы можете использовать этот класс:

  2. Изменение функций публичной библиотеки для принятия указателей на буферы вместо их внутреннего распределения . Это потенциально требует большого количества изменений на стороне библиотеки, но упрощает код на стороне C #.

РЕДАКТИРОВАТЬ: в качестве дополнения к первому предложению, вы можете использовать следующий класс:

public class HashDllAutoPtr : IDisposable
{
    [DllImport(@"C:\Hash.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void ph_dct_free(IntPtr ptr);

    public HashDllAutoPtr(IntPtr ptr)
    {
        Ptr = ptr;
    }

    ~HashDllAutoPtr()
    {
        Dispose();
    }

    public IntPtr Ptr
    {
        get;
        private set;
    }

    #region IDisposable Members

    public void Dispose()
    {
        if (Ptr != IntPtr.Zero)
        {
            ph_dct_free(Ptr);
        }
        Ptr = IntPtr.Zero;
    }

    #endregion
}

Просто создайте его экземпляр для каждого результата IntPtr. Затем вы можете либо вызвать Dispose вручную, когда вы хотите освободить память, либо вы можете просто оставить ее в подвешенном состоянии, и в конечном итоге она будет забрана GC (хотя я не рекомендую это). Подробнее об утилизации неуправляемых данных можно прочитать здесь

...