2014-09-01 60 views
0

我使用的混合組件用下面的代碼:託管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的(陣列,LEN)是一個非託管C++函數。不過,我得到以下錯誤:

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

我是新的C++/CLI,特別是混合模式的組件,所以我怎麼能解決這個問題?

+1

使用pin_ptr:http://msdn.microsoft.com/en-us/library/1dz8byfh.aspx – 2014-09-01 07:53:32

+0

不能編譯功能非託管代碼。您不能使用pin_ptr <>,當其他代碼訪問BYTE *時,該數組將不再被鎖定。返回指向數組的原始指針的最明顯的問題是調用者不知道數組可能會有多久,並且不能可靠地釋放爲數組分配的內存。您需要首先解決這些問題,然後才能考慮從託管代碼調用該功能。 – 2014-09-01 10:48:35

回答

2

爲了使非託管代碼可靠地訪問託管數據,您需要首先「管理」託管數據;然後嘗試將其傳遞到非託管API。爲此目的使用pin_ptr(並且必須在所需的非管理呼叫期間固定)。

pin_ptr具有額外的優點,它可以用於需要本地指針的地方。來自MSDN;

A pin_ptr represents a superset of the functionality of a native pointer. Therefore, anything that can be assigned to a native pointer can also be assigned to a pin_ptr . An interior pointer is permitted to perform the same set of operations as native pointers, including comparison and pointer arithmetic.

An object or sub-object of a managed class can be pinned, in which case the common language runtime will not move it during garbage collection. The principal use of this is to pass a pointer to managed data as an actual parameter of an unmanaged function call. During a collection cycle, the runtime will inspect the metadata created for the pinning pointer and will not move the item it points to.

要說明的基本代碼示例;

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和​​之間的轉換/編組在這裏按預期工作。注意;這些轉換並不是特別需要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); 
} 
+0

我真的不明白如何改變我的功能。即使有上面​​的信息,它解決了返回類型不匹配錯誤,仍然存在參數傳遞的問題,具體爲:'錯誤C2664:'cli :: array ^ComputeHashS(cli :: array ^)':不能將參數1從'BYTE *'轉換爲'cli :: array ^'' – Jason 2014-09-01 09:09:42

+0

@Jason。當回到託管的'cli :: array'時,你循環遍歷'BYTE *'中的所有元素,並適當地賦值(循環和使用索引操作符)。 – Niall 2014-09-01 09:16:19

+0

@Jason。在這種情況下,更像'void ComputeHashS(array ^Data,array ^hash)'的簽名可能會更好。或'void ComputeHashS(array ^Data,array ^%hash)' – Niall 2014-09-01 09:17:08