C# 调用C++ dl注意事项

    最近经常在C#代码调用C++的dll文件,对于遇到的坑总结一下

1、针对C++的dll文件常见的几种约定方式

__stdcal:参数从右向左的顺序进行入栈,堆栈由被调用方进行释放,即C++的dll的函数进行堆栈自行管理

__cdecl:参数从右向左的顺序进行入栈,堆栈由调用方维护,即谁调用,是负责堆栈释放

C++的默认调用约定为__cdecl,我们在编写C#时,需要注意调用函数约定方式。

2、再C#代码中,默认的调用方式为__stdcall的约定的方式,如果无相关参数传递,则无论是否表明调用约定,均不会报错

extern "C" void __declspec(dllexport)   TestWay(LPSTR lpPara)
{
	cout<<"调用了TestWay 传递参数"<<lpPara<<endl;
	return;
}

extern "C" void __declspec(dllexport) __stdcall  TestWayStdcall(LPSTR lpPara)
{
	cout<<"调用了TestWayStdcall传递参数"<<lpPara<<endl;
	return;
}

internal class TestDllWay
{
   [DllImport("TestDll.dll")]
   public extern static void TestWay(string lpPara);
   DllImport("TestDll.dll")]
   public extern static void TestWayStdcall(string lpPara);

}

 当你调用TestWay,程序会报错,当你加上CallingConvention = CallingConvention.Cdecl时,则可以调用成功!

3、CharSet.Ansi:以多字节字符串的形式封送字符串

     CharSet.Unicode:以 Unicode 2 字节字符形式封送字符串

    CharSet.Auto: 

//     针对目标操作系统适当地自动封送字符串。在 Windows NT、Windows 2000、Windows XP 和 Windows Server
        //     2003 系列上,默认值为 System.Runtime.InteropServices.CharSet.Unicode;在 Windows 98
        //     和 Windows Me 上,默认值为 System.Runtime.InteropServices.CharSet.Ansi。尽管公共语言运行时默认值为
        //     System.Runtime.InteropServices.CharSet.Auto,但使用语言可重写此默认值。例如,默认情况下,C# 将所有方法和类型都标记为
        //     System.Runtime.InteropServices.CharSet.Ansi。

编写调用C++代码时,主要编码格式,否则会有意想不到的错误

以上C++ Dll代码再多字节编码编写

修改代码

[DllImport("TestDll.dll",CallingConvention = CallingConvention.Cdecl,CharSet = CharSet.Auto)]
public extern static void TestWay(string lpPara);

再次调用是则会运行结果:

分析原因就是传递的编码格式导致这种C++char* 指针错误

4、关于传递int* 参数读取方式

extern "C" void __declspec(dllexport)  TestIntVar(int *pIntValue)
{
	*pIntValue = 10;
	cout<<"调用了TestIntVar传递参数int = "<<*pIntValue<<endl;

}

[DllImport("TestDll.dll",CallingConvention = CallingConvention.Cdecl)]
public extern static void TestIntVar(IntPtr ptr);

private void TestIntVal()
{
   int ivalue = 0;
   IntPtr ptr = Marshal.AllocHGlobal(4);
   TestDllWay.TestIntVar(ptr);
   ivalue = Marshal.ReadInt32(ptr);
   Marshal.FreeHGlobal(ptr);
}

同样也可以使用out,ref的方式获取

[DllImport("TestDll.dll",CallingConvention = CallingConvention.Cdecl)]
public extern static void TestIntVar(out int ptr);

[DllImport("TestDll.dll",CallingConvention = CallingConvention.Cdecl)]
public extern static void TestIntVar(ref int ptr);

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值