Управляемая ошибка преобразования массива 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);
}