首页 > 编程语言 >C#调用C++ 平台调用P/Invoke 字符串【三】

C#调用C++ 平台调用P/Invoke 字符串【三】

时间:2023-04-05 22:34:43浏览次数:47  
标签:调用 string Invoke C# CharSet C++ Str



Git p-invoke 源码地址

 

C#调用C++ 平台调用P/Invoke 调用约定【一】

C#调用C++ 平台调用P/Invoke 函数指针/回调函数【二】

C#调用C++ 平台调用P/Invoke 字符串【三】

C#调用C++ 平台调用P/Invoke 错误码LastError【四】

C#调用C++ 平台调用P/Invoke 结构体--输入输出参数、返回值、返出值、结构体数组作为参数【五】

C#调用C++ 平台调用P/Invoke 结构体--含有内置数据类型的一维、二维数组、字符串指针【六】

C#调用C++ 平台调用P/Invoke 结构体--内存对齐方式、union封装【七】

C#调用C++ 平台调用P/Invoke 结构体--结构体嵌套【八】


【1】字符串作为输入参数

C++代码:

EXPORTDLL_API int Str_Output( WCHAR *pStr )
{
	if (NULL == pStr)
	{
		return(-1);
	}

	wprintf(L"Str_Output %s\n", pStr);

	return(0);
}

C#代码,定义成string即可:

[DllImport("ExportDll.dll", CharSet=CharSet.Unicode)]
public static extern int Str_Output([MarshalAs(UnmanagedType.LPWStr)]string pStr);

测试:

string str = "hjkl;";
CExportDll.Str_Output(str);

【2】字符串作为参数,需要进行修改返回

C++代码:

EXPORTDLL_API int Str_Change( WCHAR *pStr, int len )
{
	if (NULL == pStr)
	{
		return(-1);
	}

	for (int ix=0; ix<len-1; ix++)
	{
		pStr[ix] = 'a' + (ix) % 26;
	}
	pStr[len-1] = '\0\0';

	wprintf(L"Str_Change %s\n", pStr);
	return(0);
}

C#代码,定义成stringBuilder类型

[DllImport("ExportDll.dll", CharSet = CharSet.Unicode)]
public static extern int Str_Change([MarshalAs(UnmanagedType.LPWStr)]StringBuilder pStr, int len);

测试:

StringBuilder strBuilder = new StringBuilder(256);
CExportDll.Str_Change(strBuilder, 256);

【3】字符串作为返回值

C++代码:

static  WCHAR *g_StrReturn = L"Str_Return";

 

EXPORTDLL_API WCHAR * Str_Return()
{
	wprintf(L"Str_Return \n");

	return(g_StrReturn);
}

C#代码,将返回值定义成IntPtr,再进行解析:

[DllImport("ExportDll.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr Str_Return();

测试:

IntPtr strPtr = CExportDll.Str_Return();
string strIntPtr = Marshal.PtrToStringUni(strPtr);

【4】字符串数组作为参数,每个元素长度为10

C++代码:

EXPORTDLL_API int Str_ChangeArr( WCHAR **ppStr, int len )
{
	if (NULL == ppStr)
	{
		return(-1);
	}

	for (int ix=0; ix<len; ix++)
	{
		if (NULL != ppStr[ix])
		{
			lstrcpyn(ppStr[ix], L"abc", 10);
		}
	}

	wprintf(L"Str_ChangeArr \n");
	return(0);
}

C#代码,定义成string[],如果数据需要返出,还必须指定In、Out参数:

[DllImport("ExportDll.dll", CharSet = CharSet.Unicode)]
public static extern int Str_ChangeArr([In, Out]string[] ppStr, int len);

测试:

string[] strArr = new string[4] {new string('\0', 10), 
                                 new string('\0', 10),  
                                 new string('\0', 10), 
                                 new string('\0', 10) };
CExportDll.Str_ChangeArr(strArr, 4);

【5】释放非托管的内存

C++代码:

EXPORTDLL_API void Str_ParameterOut( WCHAR **ppStr )
{
	if (NULL == ppStr)
	{
		return;
	}

	*ppStr = (WCHAR *)CoTaskMemAlloc(128 * sizeof(WCHAR));

	lstrcpynW(*ppStr, L"abc", 128);
	wprintf(L"Str_ReturnOut \n");
}

C#代码,此时可以使用两种方式:

自动释放内存,必须使用string接受:

//使用CoTaskMemAlloc方法申请的内存,则会自动调用CoTaskMemFree来释放非托管内存
//这就意味了托管代码无需处理内存问题,减轻了托管代码的的复杂度
//但.NET只能释放由CoTaskMemAlloc分配的内存,所以如果底层不是使用CoTaskMemAlloc申请的内存,必须定义对应的释放函数
[DllImport("ExportDll.dll", CharSet = CharSet.Unicode, EntryPoint = "Str_ParameterOut")]

手动释放内存:

//使用IntPtr接受时,需要手动释放
[DllImport("ExportDll.dll", CharSet = CharSet.Unicode, EntryPoint = "Str_ParameterOut")]
public static extern void Str_ParameterOuttPtr(ref IntPtr ppStr);

测试:

string strOut = "";
CExportDll.Str_ParameterOutString(ref strOut);
//手动释放
IntPtr strOutIntPtr = IntPtr.Zero;
CExportDll.Str_ParameterOuttPtr(ref  strOutIntPtr);
string strOut2 = Marshal.PtrToStringUni(strOutIntPtr);
Marshal.FreeCoTaskMem(strOutIntPtr);

 

标签:调用,string,Invoke,C#,CharSet,C++,Str
From: https://blog.51cto.com/u_13675550/6171816

相关文章

  • C#调用C++ 平台调用P/Invoke 函数指针/回调函数【二】
    Gitp-invoke源码地址 C#调用C++平台调用P/Invoke调用约定【一】C#调用C++平台调用P/Invoke函数指针/回调函数【二】C#调用C++平台调用P/Invoke字符串【三】C#调用C++平台调用P/Invoke错误码LastError【四】C#调用C++平台调用P/Invoke结构体--输入输出参数、返回值、返......
  • C++/CLI 托管C++的数组介绍【4】
    Git源码地址 C++/CLI托管C++的托管与非托管字符串的相互转换【1】C++/CLI托管C++的数据类型介绍【2】C++/CLI托管C++的基本数据类型及函数【3】C++/CLI托管C++的数组介绍【4】C++/CLI托管C++之字符串封装【5】C++/CLI托管C++之enum枚举封装【6】C++/CLI托管C++之类、属性......
  • pycharm创建文件时自动生成注释
    参考:https://blog.csdn.net/weixin_52696285/article/details/128498933 File----Settings-----FileandCodeTemplates-----PythonScript写入如下模板:'''@Project:${PROJECT_NAME}@File:${NAME}.py@IDE:${PRODUCT_NAME}@Author:雨薇@Date:${D......
  • Win10 安装Oracle21c 教程
    Win10安装Oracle21c教程1:(官方)下载地址https://www.oracle.com/database/technologies/oracle21c-windows-downloads.htmlOracleDatabase21c (21.3)OracleDatabase21c (21.3)forMicrosoftWindowsx64(64-bit)DownloadDescriptionWINDOWS.X64_2130......
  • cpp shared_future
    #include<chrono>#include<ctime>#include<future>#include<iomainp>#include<iostream>#include<sstream>#include<uuid/uuid.h>std::stringget_time_now(){std::chrono::time_point<std::chrono::high_......
  • MySQL登录时出现Access denied for user ‘root‘@‘localhost‘ (using password: YE
    发现是springboot结合JDBC时,我这里输入纯数字加点,就会出现这个问题。  后来我改数据库密码,改成字母开头的数据库密码,就可以了。 但是有个奇怪的是,我方式数字+点的密码是复制过去的,当时idea的编辑器,打开该密码是橙色的。可能是我当时复制的格式有问题。我现在输入并没有......
  • oracle 中Version counts高原因分析
    (18条消息)Oracle高Versioncounts问题说明_Dave的博客-CSDN博客主要查看视图v$sqlareav$sql_shared_cursor ......
  • The Many Ways To Call Axes In Matplotlib
    %matplotlibwidgetfromIPython.displayimportdisplay,HTMLimportrefrompathlibimportPathimportcv2importnumpyasnpimportmatplotlib.pyplotaspltfrompprintimportpprintimportclipboardimportpandasaspdimportconcurrent.futuresimportt......
  • Linux静默安装Oracle21C
    Linux静默安装Oracle21C1、修改主机名及配置hosts[root@localhost~]#hostname #查看主机名[root@localhost~]#hostnameoracledb #修改主机名[root@localhost~]#vim/etc/hosts #修改hosts[root@localhost~]#cat/etc/hosts2、关闭selinux和防火墙[root@l......
  • LinkedBlockingDeque介绍
    //有一个内部类finalclassNode<E>,//用于包装每个节点的数据。另外有成员属性//Node<E>first,Node<E>last,//当前拥有元素数量intcount,容量intcapacity;//Eitem当前节点数据//Node<E>prev指向当前节点前驱节点......