这阵在做C++动态库与C#相互调用的工作,遇到C#获得C++字符串的问题,解决问题时发现也有不少人在问。
自己已经完成了这一部分功能的封装,把代码贴出来供大家分享。
环境:PC VS2008
C#定义委托GetCStringFunction,用于传递希望在C++调用的返回wstring的函数。GetCString调用委托,并把返回的指向wstring的指针转为C# string输出,然后删除掉C++中创建的存储wstring的内存。
C#通过委托在C++中调用的函数在获得C++ wstring后调用CString2CSharpIntPtr创建内存,把wstring存储在此处,并把指针返回给C#。然后等待c#调用DeleteStrMemory释放该内存。
其中的DDInterfaceX pDDInterfaceX是传递的一个C++中类使用的指针,用于C++中调用类成员函数获得wstring。这部分与本题目无关,可略过。
C#代码:
using System.Runtime.InteropServices;//使用DllImport导入C++ Dll需要此命名空间
GeneralMarco.DDImport== @"..\..\..\debug\CommTest.dll";//存储C++ Dll位置
//功能:用于获得C++环境下的pItemRef(优先)和pItem指向的String数据//输入:DDInterfaceX pDDInterfaceX的pItemRef(优先)和pItem
//输出:用于转换成字符串的指针DestinationStrPtr
//返回值:0 成功,1 失败,2 VIRTUALCALLERR
public delegate int GetCStringFunction(ref DDInterfaceX pDDInterfaceX, ref IntPtr DestinationStrPtr);
[DllImport(GeneralMarco.DDImport)]
//功能:在C++中释放获得C++字符串时分配的内存
//输入:StringPtr
//输出:无
//返回值:返回true为成功
public static extern bool DeleteStrMemory(IntPtr StringPtr);
//功能:C#程序封装,用于获得C++运行环境下的String数据。
//输入:DDInterfaceX pDDInterfaceX的pItemRef(优先)和pItem,SourceFunction为调用的C++方法
//输出:DestinationString,获得string
//返回值:0 成功,非0 失败
//Example:
//DDInterface.GetCStringFunction GetStringFunc;
//GetStringFunc = DDInterface.GetLabel;
//string str;
//DDInterface.GetCString(out str, ref myDDInterface.pDDInterfaceX, GetStringFunc);
public static int GetCString(out string DestinationString, ref DDInterfaceX pDDInterfaceX, GetCStringFunction SourceFunction)
{
int returnCode=0;
IntPtr DestinationStrPtr = new IntPtr();
returnCode = SourceFunction(ref pDDInterfaceX, ref DestinationStrPtr);//获得字符串指针指向相应的C++字符串;
DestinationString = System.Runtime.InteropServices.Marshal.PtrToStringAuto(DestinationStrPtr);//将字符串指针转为字符串;
DDInterface.DeleteStrMemory(DestinationStrPtr);//释放C++内存;
return returnCode;
}
[DllImport(GeneralMarco.DDImport)]
//功能:获得DD item项的Label,返回到DestinationStrPtr
//输入:DDInterfaceX 结构体引用
//输出:DestinationStrPtr 指针
//返回值:0 成功,非0 失败
public static extern int GetLabel(ref DDInterfaceX pDDInterfaceX,ref IntPtr DestinationStrPtr);
#define DDExport extern "C" __declspec(dllexport)
DDExport int GetLabel(DDInterfaceX* pDDInterface,wchar_t** DestinationStr)
{
//将pDDinterface->m_pItem或pDDInterface->m_pItemRef中的标签返回到C# string 指针DestinationStr。
//返回值0成功,其他失败
wstring szLabel, dummyHelp;// try wide 28jan08
bool stringFull = false;
RETURNCODE rc=0;
if (pDDInterface->m_pItemRef)//如果有关联项,需要通过关联项获得label?
{
rc=rc||pDDInterface->m_pItemRef->getItemLabel(szLabel, stringFull,dummyHelp); // could be different from item label
}
if ( szLabel.empty() && GetItem(pDDInterface) )//自己得到label
{
rc=rc||pDDInterface->m_pItem->Label(szLabel);
}
rc=rc||CString2CSharpIntPtr(szLabel.c_str(),DestinationStr);
return rc;
}
int CString2CSharpIntPtr( CString SourceStr,wchar_t** DestinationStr)
{//将C++Cstring SourceStr数据转为C# String,以ref intptr形式传回,返回值0成功,其他失败。
RETURNCODE rc=0;
int len = sizeof(wchar_t) * (SourceStr.GetLength() + 1) ;
*DestinationStr = new wchar_t[len];
memset(*DestinationStr, 0, len);
rc=wcscpy_s(*DestinationStr, len, CT2CW(SourceStr));
return rc;
}
DDExport bool DeleteStrMemory(void *CSharpIntPtr)
{//释放CString2CSharpIntPtr中的内存空间
if (CSharpIntPtr != NULL)
{
delete CSharpIntPtr;
CSharpIntPtr = NULL;
}
return true;
}