一个在C++/CLI中手工列集System::String的辅助工具

虽然在C++/CLI中调用DLL里的native函数时,P/Invoke可以自动把System::String 列集成C字串(const char*或const wchar_t*),但有的时候我们仍然需要手工 列集System::String。比如当出现以下情况时:1.托管代码要调用同属一个mixed assembly里的非托管函数(比如和一个 非托管 静态库链接),并传递一个字串,此时P/Invoke自动列集不能发挥作用,因为这项功能只针对从DLL里导入的函数。2.调用一个以非托管指针操作C字串的托管函数,如编译成IL代码的老的C/C++函数。为了简便手工列集System::String,我写了几个辅助类。以下例子说明如何使用:
#include  < iostream >

#include "StringMarshaller.h"


int  main()
{
using   namespace  std;
using   namespace  System;
 
 String
^  s1  =   " sometimes  " ;
 String
^  s2  =   " C++/CLI  " ;
 String
^  s3  =   " sucks " ;

 wcout 
<<  ( const  wchar_t * )StringMarshaller::MarshalStringUni(s1);
 cout 
<<  StringMarshaller::MarshalStringAnsi(s2);
 wcout 
<<  ( const  wchar_t * )StringMarshaller::MarshalStringPin(s3)  <<  endl;
}
可以看到在StringMarshaller.h的名字空间StringMarshaller里有三个“函数”MarshalStringUni, MarshalStringAnsi和MarshalStringPin。其中前两个要将传递的内容进行一次拷贝,最后一个不拷贝,但是会在被调用函数返回之前pin住传递的System::String。MarshalStringPin得到的是unicode字串,因为CLR中的字串是以unicode方式储存的。需要注意的是使用这三个“函数”的条件是被调用函数不会保存传入的const char或const wchar_t指针,因为被调用函数返回后这些指针就失效了。
以下是StringMarshaller.h的源码:
#pragma  once
#include  < vcclr.h >

namespace  StringMarshaller  {
using namespace System;
using namespace System::Runtime::InteropServices;
/////////////////////////////////////////////////////////////////////
  // The copying version
template<typename CharT> // CharT = char or unsigned char or wchar_t
class copy_marshaller
{
 IntPtr m;

public:
 copy_marshaller(IntPtr x) 
{ m=x; }
 
 
operator const CharT*() 
 
return static_cast<const CharT*>(m.ToPointer()); }
 
 
~copy_marshaller() 
 
{ Marshal::FreeHGlobal(m); }
}
;

#define DEFINE_MarshalString(encoding, type)\
struct MarshalString##encoding: public copy_marshaller<type>\
{\
 MarshalString##encoding(String
^ s)\
 : copy_marshaller
<type>(Marshal::StringToHGlobal##encoding(s))\
 
{}\
}
;

DEFINE_MarshalString(Ansi, 
char) //
MarshalStringAnsi
DEFINE_MarshalString(Uni, wchar_t) // MarshalStringUni

/////////////////////////////////////////////////////////////////////
  // The pining version.
class MarshalStringPin
{
 GCHandle h;

public:
 MarshalStringPin(String^ s)
 {
  h = GCHandle::Alloc(s, GCHandleType::Pinned);
 }

 operator const wchar_t*()
 {
   return reinterpret_cast<wchar_t*>(
    h.AddrOfPinnedObject().ToPointer());
 }

 ~MarshalStringPin() 
 {
  h.Free();
 }
};

}





你可能感兴趣的:(String)