Как вернуть массив байтов из C++ в C#

поэтому я немного боролся с этим. Я пытаюсь сделать свою собственную библиотеку AES 128 для использования с одной из моих программ. Библиотека тестирует и работает на C++ (хорошо для функции шифрования.. Я не реализовал другие) функция "шифровать" выглядит так:

НОВЫЙ КОД

void Aes128Class::EncryptBlock(BYTE* outBlock, const BYTE* inBlock, const BYTE* cipherBlock)
{
    BYTE temp[16] = {0x00};
    Galois::XorBlock(temp, inBlock);
    Galois::XorBlock(temp, cipherBlock);

    BYTE expandedKey[176] = {0x00};
    memcpy(expandedKey, Key, 16);
    Galois::expand_key(expandedKey);

    Galois::XorBlock(temp, expandedKey);
    for(int i=16; i<160; i+=16)
    {
        Galois::DoRound(temp, &expandedKey[i]);
    }
    Galois::SubBytes(temp);
    Galois::ShiftRows(temp);
    Galois::XorBlock(temp, &expandedKey[160]);

    memcpy(outBlock, temp, 16);
}
void Aes128Class::EncryptData(BYTE* outBlock, size_t& outlen, const BYTE* inBlock, size_t length)
{
    float blockSize = (float)(length/16);
    blockSize = ceilf(blockSize);
    int newLength = (int)(blockSize*16);
    BYTE* temp = (BYTE*)malloc(newLength);
    BYTE* padd = (BYTE*)malloc(newLength);
    memset(temp, 0, newLength);
    memcpy(padd, inBlock, length);
    EncryptBlock(temp, padd, IV);
    for (int i=1; i<blockSize; i++)
    {
        EncryptBlock(&temp[i*16], &padd[i*16], &temp[(i-1)*16]);
    }
    outlen = newLength;
    memcpy(outBlock, temp, newLength);
}

идея в том, что если plainText не находится в 16-байтовом приращении блока, тогда я заставляю его быть. Таким образом, это создает массив байтов переменного размера. Он работает в моем C++ тесты, но когда я вызываю его в C# Я получаю несколько разных ошибок... Это займет минуту, чтобы описать.

    [DllImport("CppAes128.dll", CallingConvention = CallingConvention.ThisCall,
        EntryPoint = "?EncryptData@Aes128Class@@QAEXPAEAAIPBEI@Z")]
    static extern void EncryptData(IntPtr pClass, ref IntPtr outblock, [Out]int OutLength, byte[] inBlock, int length);

когда я называю это, я получаю действительные указатели на оба array, и outlength. То, как это выглядит сейчас, вызывает нарушение доступа, но я могу заставить эту структуру работать, если я изменю [Out]int OutLength to ref IntPtr. Интересно, если я сделаю ref int или ref uint она все еще "работает". Поэтому, если я это сделаю, я попытаюсь прочитать intptr и тогда я получаю доступ нарушение. Я компилирую это как x86 project на .NET 4.0 (так как я где-то читал, что 3.5 имел некоторые ошибки с доступом...)

вот что я пробовал в C#. Это немного искажено, поскольку я играл с ним в течение нескольких часов (извините):

    public byte[] EncryptData(byte[] plainText, int length)
    {
        byte[] enc = null;
        int len = 0;
        IntPtr pArray = IntPtr.Zero;
        EncryptData(theClass, ref pArray, len, plainText, length);

        Console.WriteLine(len);
        //enc = new byte[len];
        //Marshal.Copy(pArray, enc, 0, len);
        //Marshal.Release(pArray);
        //try
        //{
        //    int elementSize = Marshal.SizeOf(typeof(IntPtr));
        //    //IntPtr unmanagedArray = Marshal.AllocHGlobal(10 * elementSize);
        //    Console.WriteLine("Reading unmanaged memory:");
        //    // Print the 10 elements of the C-style unmanagedArray 
        //    for (int i = 0; i < 10; i++)
        //    {
        //        Console.WriteLine("{0:X2}:", Marshal.ReadByte(pArray, i));
        //    }

        //    Marshal.FreeHGlobal(pArray);

        //}
        //catch (Exception ex)
        //{
        //    Console.WriteLine("{0}n{1}", ex.Source, ex.Message);
        //    Console.WriteLine("Win32({0})", Marshal.GetLastWin32Error());
        //}
        //Marshal.Release(pArray);
        return enc;
    }

единственный раз, когда это сработало, когда я просто сделал массив статического размера и не использовал ref или marshal "копировать" или что-нибудь.. Я думаю, что моя подпись была чем-то вроде этого

static extern void EncryptData(IntPtr pClass, byte[] outBlock, byte[] inBlock, int length);

это почти сработало, но проблема в том, что когда я сделал foreach петля На array он всегда был размер, который я поставил.. по меньшей мере, неприятно.

так что же я делаю не так? как я могу заставить это работать? Я так расстроена этим. Спасибо

О и FYI, это так, что я не могу зависеть от

2 ответов


Если вы все еще ищете ответ, этот пример дает отправную точку.

в основном, начните с выделения блока памяти в вызове собственной функции, а затем вызовите обратный вызов в управляемый, где вы передаете ( по ref ) массив и его размер, сохраненный из исходного списка входных параметров.

таким образом, вы выделяете блок памяти для управляемого кода в управляемом коде и редактируете его с содержимым из родной.

http://msdn.microsoft.com/en-us/library/ektebyzx.aspx

альтернативный метод было бы неплохо найти, сравнение производительности было бы бонусом:)


честно говоря, я нашел самый простой способ сделать это-обернуть неуправляемый вызов C++ управляемым вызовом c++. В управляемом c++ вы можете скопировать данные прямым способом C++ (закрепив структуру данных) и передать ее обратно в C#