2014-02-03 6 views
1

Я вызываю dll C++ из своей программы на C#. DLL состоит из нескольких функций, и я могу вызвать большинство из них, кроме этого.Как сохранить переменную uint8_t *, возвращаемую функцией C++ в C#?

Функция C++, подобно, как показано ниже:

__declspec(dllexport) uint8_t* myHash(const char *filename) 
    { 
     uint8_t *hash = (unsigned char*)malloc(72*sizeof(uint8_t)); 
     //some processing on hash 
     return hash; 
    } 

Как можно видеть в коде выше, хэш-функция хранит массив символов. Я хочу получать значения в моей программе на C#, но я не могу это сделать.

Мой C# код, как ниже:

[DllImport("myHash.dll", CharSet = CharSet.Ansi)] 
     public static extern IntPtr myHash(string filename); 

    IntPtr ptr = myHash(fileA); 
      char[] result = new char[72]; 
      Marshal.Copy(ptr, result, 0, 72); 

ответ

3

Проблема заключается в том, что char в C# является 16 бит элемента символов. Ваш код на C++ возвращает массив из 8 бит uint8_t значений. Вместо этого вы должны переключиться на использование байтового массива.

[DllImport("myHash.dll", CallingConvention=CallingConvention.Cdecl, 
    CharSet = CharSet.Ansi)] 
public static extern IntPtr myHash(string filename); 
.... 
IntPtr ptr = myHash(fileA); 
byte[] result = new byte[72]; 
Marshal.Copy(ptr, result, 0, 72); 

я указал на соглашение о вызовах, потому что, как написано, ваша функция __cdecl. Возможно, вы опустили что-то в расшифровке вопроса, но вышеприведенная декларация соответствует неуправляемому коду в вопросе.

Эта функция была бы намного лучше разработана, чтобы позволить вызывающему абоненту выделить буфер. Это позволяет избежать экспорта деаллокатора из кода C++. Я бы написать C++ вроде этого:

__declspec(dllexport) int myHash(const char *filename, uint8_t* hash) 
{ 
    // calculate hash and copy to the provided buffer 
    return 0; // return value is an error code 
} 

И соответствующий C# код:

[DllImport("myHash.dll", CallingConvention=CallingConvention.Cdecl, 
    CharSet = CharSet.Ansi)] 
public static extern int myHash(string filename, byte[] hash); 
.... 
byte[] hash = new byte[72]; 
int retval = myHash(fileA, hash); 

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

Обратите внимание, что хотя вы ссылаетесь на вывод этой функции в виде массива символов, использование uint8_t* делает более вероятным быть байтовым массивом. Если это действительно массив символов, вы можете использовать Encoding.GetString() для преобразования в строку.

+0

Я попробовал первое решение, которое вы предоставили с помощью байта []. Это дает мне ценности, которые, я сомневаюсь, неверны. –

+0

Первый раздел кода в моем ответе соответствует коду в вопросе. Если возникнет проблема, то наверняка будет либо, что код в вопросе отличается от кода, который вы используете, либо ваш неуправляемый код не ведет себя так, как вы ожидаете. –

+0

Повторяю. Код в моем ответе соответствует этому вопросу. Возможно, вам хотелось бы объяснить, почему вы считаете, что значения 250, 162, 234 и т. Д. Не являются разумными значениями для поиска в байтовом массиве байтов. Байт имеет значения в диапазоне 0..255. Значения, которые вы упомянули, похоже, вполне соответствуют этому счету. –

Смежные вопросы