Как вернуть массив байтов из 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#