【问题标题】:Managed C++/CLI Array Conversion Error托管 C++/CLI 数组转换错误
【发布时间】:2014-09-01 07:38:01
【问题描述】:

我正在使用带有以下代码的混合程序集:

#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) 是一个 UNMANAGED C++ 函数。但是,我收到以下错误:

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

我是 C++/CLI 的新手,尤其是混合模式程序集,我该如何解决这个错误?

【问题讨论】:

  • 您不能将该函数编译为非托管代码。您不能使用 pin_ptr,当其他代码访问 BYTE* 时,该数组将不再被固定。返回指向数组的原始指针最明显的问题是调用者不知道数组可能有多长,并且不能可靠地释放为数组分配的内存。在考虑从托管代码调用函数之前,您需要先解决这些问题。

标签: arrays c++-cli clr managed


【解决方案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::ByteBYTE 之间的转换/编组在这里按预期工作。笔记;这里的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);
}

【讨论】:

  • 我真的不明白如何改变我的功能。即使上面的信息解决了返回类型不匹配错误,参数传递仍然存在问题,具体是:error C2664: 'cli::array&lt;unsigned char,1&gt; ^ComputeHashS(cli::array&lt;unsigned char,1&gt; ^)' : cannot convert argument 1 from 'BYTE *' to 'cli::array&lt;unsigned char,1&gt; ^'
  • @Jason。回到托管 cli::array 时,您循环遍历 BYTE* 中的所有元素并适当地分配值(循环并使用索引运算符)。
  • @Jason。在这种情况下,更像void ComputeHashS(array&lt;System::Byte, 1&gt; ^Data, array&lt;System::Byte, 1&gt;^ hash) 的签名可能会更好。或void ComputeHashS(array&lt;System::Byte, 1&gt; ^Data, array&lt;System::Byte, 1&gt;^% hash)
  • 我不能在 DoWork() 函数中使用托管类型,因为我有 #pragma unmanaged 并且希望这个函数是非托管的...
  • 并且不能在 ComputeHashS() 函数中使用非托管类型(#pragma managed 标签)...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-24
  • 2023-03-12
  • 1970-01-01
相关资源
最近更新 更多