我使用的是一个带有以下代码的混合程序集:
#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的新手,尤其是混合模式程序集的新手,所以如何解决此错误?
为了使非托管代码能够可靠地访问托管数据,您需要首先"固定"托管数据;在尝试将其传递到非托管的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
之间的转换/编组按预期工作。笔记CCD_ 8在这些转换中不是特别需要的,因为非托管代码从不访问托管数组中的数据(对于更一般的情况,它保留为注释)。
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);
}