Проблема в вызове функции C ++ dll из C # - PullRequest
1 голос
/ 30 марта 2009

Это мой 3-й поток, касающийся проблемы Blowfish в C #. Несмотря на то, что я не могу внедрить Blowfish в свое приложение, я решил использовать его как внешнюю C ++ DLL. Обратите внимание, что я пробовал Blowfish.NET и любые другие, проблема в том, что я переводил код с C ++ на C #, и код C # должен делать то же самое, что и код C ++.

Пока:

---> Источник C ++ DLL <--- </a>

Обратите внимание, что экспортируемые функции находятся в конце кода

код C # (определение)

    [DllImport("TestDLL.dll", EntryPoint = "Initkey" ,ExactSpelling = true , CallingConvention = CallingConvention.Cdecl)]
    public static unsafe extern void Initkey(byte[] key);

    [DllImport("TestDLL.dll", EntryPoint = "encode", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
    public static unsafe extern void encode(UInt32 *stream);

код C # (вызов функции)

-Инициализировать ключ blowfish

UInt32[] keyarray = new UInt32[2];
//some code
Extern.Initkey(Misc.ConvertFromUInt32Array(keyarray));
//
//
//Helper function used to convert a UInt32 array into Byte array.
public static byte[] ConvertFromUInt32Array(UInt32[] array)
{
    List<byte> results = new List<byte>();
    foreach (UInt32 value in array)
    {
        byte[] converted = BitConverter.GetBytes(value);
        results.AddRange(converted);
    }
    return results.ToArray();
}

-Кодировать данные.

            UInt32[] keyarray2 = new UInt32[2];
            //some code
            unsafe
            {
                fixed (UInt32* LPBYTE = keyarray2)
                {
                    Extern.encode(LPBYTE);
                }
            }

После того, как keyarray2 перезаписан функцией Encode, я проверяю значения в коде C ++, расшифровывая их, чтобы убедиться, что все в порядке.

Ну, это не хорошо. Это моя проблема, поэтому я прошу вас о помощи.

Значения отличаются, когда я дешифрую их, но если я зашифрую их и расшифрую в источнике C ++, они будут равны. Код C ++ абсолютно одинаков, за исключением того, что нет DLL, поскольку код находится в C ++.

Может ли это быть из-за функции Initialize. Несколько месяцев назад я читал, что массивы в C ++ передаются как указатели. Я не верю в это, но даже в этом случае - может ли это быть проблемой?

Я не могу найти подсказку. Я потратил впустую свою жизнь с этим Blowfish в C #. По крайней мере, это решение должно работать, но это не так - Почему?

Ответы [ 4 ]

1 голос
/ 30 марта 2009

Чтобы добавить к тому, что сказал Яхимко, также проверьте документацию для BitConverter - вы должны быть уверены, что передаете ключ и данные в порядке байтов, который вы намеревались. Примечание. Из предыдущего потока я успешно зашифровал данные с помощью модифицированного шифратора Blowfish.NET и получил его в соответствии с результатом вашего кода C ++.

1 голос
/ 30 марта 2009

Вам известно о том, что вы инициализируете временный экземпляр, который уничтожается к моменту возврата функции Initkey? Вы должны объединить все это в одну функцию или создать cBlowfish в куче и вернуть указатель на код C # (он может обрабатывать его как непрозрачный IntPtr).

Кроме того, вам не нужно использовать небезопасные здесь. Просто передайте UInt32 [] напрямую.

0 голосов
/ 30 марта 2009

Возможно, вам следует попробовать использовать ref для указателей и out для функций, которые возвращают данные через аргумент. Дай мне знать, если это работает. Спасибо.

0 голосов
/ 30 марта 2009

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

Недавно я боролся с передачей массива байтов из C # в функцию C, и мне пришлось маршалировать данные в обоих направлениях. Для меня не очевидно, что ваш код делает это.

Лучше, чем объяснение, я приведу конкретный пример:

//extern "C" LIBEXIFWRAPPER_API void findEXIFtagValue( void * load, unsigned int tagID, char* buf, int bufLen );
[DllImport("libexif-wrapper.dll")]
unsafe public static extern IntPtr findEXIFtagValue([MarshalAs(UnmanagedType.SysUInt)]IntPtr load, int tagID, [MarshalAs(UnmanagedType.SysUInt)]IntPtr buf, int bufLen); 

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

В следующем фрагменте показано, как объявляется байтовый массив, передается в функцию C и извлекаются результаты:

const int tagBuffer = 1024;
IntPtr buf = Marshal.AllocHGlobal(tagBuffer);

findEXIFtagValue(loader, (int)ExifTag.EXIF_TAG_DATE_TIME, buf, tagBuffer);
string s = Marshal.PtrToStringAnsi(buf);

Обратите внимание, что аргумент маршалируется в прототипе и снова маршалируется для получения результата.

Ничего из этого не было особенно очевидно для меня. Кажется, что IntPtr является эквивалентом void * в C #, за исключением того, что мне пришлось использовать SysUInt для управления (C) void *. Указатель на байтовый массив маршалируется как SysUInt.

(из C # noob)

НТН

...