Управляемая ошибка преобразования массива C++/CLI

Я использую смешанную сборку со следующим кодом:

#include "stdafx.h"

#pragma managed

using namespace System::Security::Cryptography;

array<System::Byte, 1> ^ComputeHashS(array<System::Byte, 1> ^Data) {

    RIPEMD160Managed^ r = gcnew RIPEMD160Managed();

    return r->ComputeHash(Data);

}

#pragma unmanaged

BYTE *DoWork(BYTE *Data) {
    BYTE *n = ComputeHashS(Data);
    return DoSomething(n, 20);
}

где DoSomething(array, len) - НЕИЗМЕННАЯ функция C++. Однако я получаю следующую ошибку:

argument of type "BYTE *" is incompatible with parameter of type "cli::array<unsigned char, 1> ^".

Я новичок в C++/CLI и особенно в сборках смешанного режима, так как я могу решить эту ошибку?

1 ответ

Решение

Чтобы неуправляемый код имел надежный доступ к управляемым данным, вам необходимо сначала "закрепить" управляемые данные; прежде чем пытаться передать его в неуправляемый API. использование pin_ptr для этой цели (и он должен быть закреплен на время требуемого неуправляемого вызова).

pin_ptr имеет дополнительное преимущество в том, что его можно использовать там, где нужен собственный указатель. Из MSDN;

pin_ptr представляет расширенный набор функциональных возможностей родного указателя. Поэтому все, что может быть назначено собственному указателю, также может быть назначено pin_ptr, Внутренний указатель может выполнять тот же набор операций, что и собственные указатели, включая сравнение и арифметику указателей.

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

Базовый пример кода для иллюстрации;

int main()
{
    array<System::Byte>^ a = gcnew array<System::Byte>(10);
    cli::pin_ptr<System::Byte> p = &a[0];
    unsigned char* b = p;
}

Принимая во внимание требования к управляемой / неуправляемой функции и данным, может оказаться более целесообразным изменить управляемую функцию ComputeHashS() работать с неуправляемыми данными (смешанный режим) и разрешать ему выполнять соответствующие преобразования. Преобразование / сортировка между System::Byte а также BYTE здесь работает как положено. Заметка; pin_ptr здесь специально не требуется с этими преобразованиями, так как неуправляемый код никогда не обращается к данным в управляемом массиве (он оставлен как закомментированный для более общего случая).

cli::array<Byte>^ marshal_array(std::vector<BYTE> const& src)
{
    cli::array<Byte>^ result = gcnew cli::array<Byte>((int)src.size());
    if (src.size()) {
        //cli::pin_ptr<Byte> pinned = &result[0];
        for (std::size_t i = 0; i < src.size(); ++i) {
            result[(int)i] = src[i];
        }
    }
    return result;
}

std::vector<BYTE> marshal_array(cli::array<Byte>^ const& src)
{
    std::vector<BYTE> result(src->Length);
    if (src->Length) {
        //cli::pin_ptr<Byte> pinned = &src[0];
        for (int i = 0; i < src->Length; ++i) {
            result[(std::size_t)i] = src[i];
        }
    }
    return result;
}

void ComputeHashS(std::vector<BYTE> in, std::vector<BYTE>& out)
{
    array<System::Byte, 1>^ Data = marshal_array(in);
    RIPEMD160Managed^ r = gcnew RIPEMD160Managed();
    array<System::Byte, 1>^ result = r->ComputeHash(Data);
    out = marshal_array(result);
}
Другие вопросы по тегам