C++托管代码调用非托管代码中的封送处理

本文详细介绍了C++托管代码如何调用非托管代码时进行封送处理,包括Unicode和Ansi字符串的双向转换、数组的处理、结构体的传递、回调函数和委托的应用,并强调了pin_ptr指针的角色和GCHandle在防止对象回收中的作用。总结中提及了marshal_as和marshal_context在封送处理中的应用。

C++托管代码调用非托管代码中的封送处理



字符串

Unicode字符串

非托管C++托管C++
wchar_t*String^

托管转非托管

  • 使用PtrToStringChars 需引用< vcclr.h >
//使用pin_ptr模板阻止被垃圾回收
pin_ptr<const wchar_t> pStr = PtrToStringChars(rawString);
  • 使用Marshal
             IntPtr pStrPtr = Marshal::StringToHGlobalUni(rawString);
             const wchar_t* pStr = static_cast<wchar_t*>(pStrPtr.ToPointer());


//最后释放掉封送到非托管内存中字符串
           Marshal::FreeHGlobal(pStrPtr);

非托管转托管

用gcnew String(buff) 将wchar_t*作为构造函数参数传给String,
同时释放作为非托管函数返回的字符串内存
delete [] buff

Ansi字符串

非托管C++托管C++
char*String^

托管转非托管

  • 使用Marshal
            IntPtr pStrPtr = Marshal::StringToHGlobalAnsi(rawString);
            const char* pStr = static_cast<char*>(pStrPtr.ToPointer());


//最后释放掉封送到非托管内存中字符串
           Marshal::FreeHGlobal(pStrPtr);

非托管转托管

用gcnew String(buff) 将char*作为构造函数参数传给String
同时释放作为非托管函数返回的字符串内存
delete [] buff

数组

封送托管C++中的数组类型:由于数组类型是托管类型,因此在传递数组作为参数调用非托管函数时,一定要防止数组被垃圾回收器回收或移动。使用pin_ptr模板阻止对数组的垃圾回收。通过向非托管函数提供GC堆中的固定指针,可避免自制数组副本的开销。

pin_ptr<int> pArray = &intArr[0];

pin_ptr指针的特性

  • 锁定托管对象中的子对象等效于锁定整个托管对象
  • 如果该指针被重新赋值,则原先指向的托管对象将不再被锁定
  • 当指针超出作用域,则原先指向的托管对象将不再被锁定,而且也不必显式解除锁定
  • pin_ptr仅允许在栈上被声时为非静态局部变量。

结构体

直接使用非托管代码中定义的结构体,传结构体的指针即可。
但当其它托管语言调用时,不能直接使用结构指针。

回调函数和委托

非托管代码中定义回调函数,托管代码中定义相应的委托

            GCHandle gchDelegate = GCHandle::Alloc(func); //GCHandle可以防止委托对象被回收  func为非托管代码委托的实例
            IntPtr pFunc = Marshal::GetFunctionPointerForDelegate(func);
            PCallbackFunc pcbFunc = static_cast<PCallbackFunc>(pFunc.ToPointer());
gchDelegate.Free();  //最后释放掉

这时没用pin_ptr,原因:可以锁定委托对象,以防止垃圾回收器将其移动或释放,但只要保证委托对象不被回收就足够了,而并不需要将其锁定。因为垃圾回收器移动委托对象的行为并不会影响其底层的回调函数。 GCHandle.Alloc方法恰好具有防止释放而又允许移动的特点,因此使用GCHandle有助于减少托管堆上的内存碎片。

总结

在本机代码和托管代码之间进行封送处理还可以用marshal_as 方法和marshal_context类完成
如果要把非托管字符串转换为托管字符串,只需要使用

// marshal_as_test.cpp
// compile with: /clr
#include <stdlib.h>
#include <string.h>
#include <msclr\marshal.h>

using namespace System;
using namespace msclr::interop;

int main() {
   const char* message = "Test String to Marshal";
   String^ result;
   result = marshal_as<String^>( message );
   return 0;
}

C++中的封送处理

隐式Pinvoke

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值