C#调用C++的DLL的解决方案

1、  引言

为了缩短界面开发成本,加上.NET集成开发环境与现代智能手机(windows mobile)系统的无缝整合,于是决定新的项目使用C#进行开发。以前的dll一直使用C++进行开发,如果重新使用C#改装,势必增加人力、时间成本,C# 提 供了调用P/Invoke机制,通过[DllImport]声明要调用的dll,可以调用C++的dll,于是复用以前的API无疑是最节省成本的方案。 本文只是通过解决具体的某类调用问题展开,给出可行的解决方案,至于结构的传出等其他类型调用、C#的非托管非安全指针的调用等, 有待进一步深入。

2、  问题描述

C++里API定义:HRESULT WINAPI XMFunc ( DWORD cbInput , BYTE * pInput , DWORD * cbOutput , BYTE ** ppOutBufferput , IRAPIStream * pStream );

其中:输入参数cbInput,pInput;

      输出参数cbOutput,ppOutBufferput,pStream(为null);

      * pcbOutput = ( DWORD ) SysStri ngByteLen ( bstrXML );

          * ppOutBufferput = ( BYTE *) LocalAlloc ( LPTR , (* pcbOutput )+1);

          memcpy ( * ppOutBufferput , ( const void *) bstrXML , * pcbOutput );

也就是说,cbOutput返回 unicode 字符 所占byte 个数 ;ppOutBufferput指针指向返回字符串的一块内存。

3、  解决方案1

C#中声明: [ DllImport ( "// XMDLL .dll" , CharSet = CharSet . Unicode , SetLastError = true )]

p ublic static extern int XMFunc(int cbInput, IntPtr pInput, ref int pcbOutput,ref string pOutBuffer,IntPtr pStream);

调用:

i nt cbInput = 0;

IntPtr pInput = IntPtr.Zero;

i nt cbOutput = 0;

String pOutBuffer = “”

i nt n Ret = XMFunc(cbInput,pInput,ref cbOutput,ref pOutBuffer,IntPtr.Zero);

结果测试:cbOutput、pOutBuffer都返回正确结果。不过dll中 * ppOutBufferput 指针没有释放,会引起内存泄露。可以在dll中定义一个释放内存的API, 调用该API进行内存释放。

4、  解决方案2

C++中增加一个API:int WINAPI XMFuncEx(DWORD cbInput,BYTE* pInput,DWORD *pcbOutput, w char_t ** pOutBuffer , IRAPIStream * pStream )

{

BYTE *pbtOutput = NULL;

int nRet = XMFunc(cbInput,pInput,pcbOutput,&pbtOutput,NULL);

if (pbtOutput)

  * pOutBuffer = ( wchar_t *) pbtOut ;

return nRet;

}

C#中声明: [ DllImport ( "// XMDLL .dll" , CharSet = CharSet . Unicode , Set LastError = true )]

P ublic static extern int XMFunc Ex (int cbInput, IntPtr pInput, ref int pcbOutput,ref IntPtr pOutBuffer,IntPtr pStream);

调用:

int cbInput = 0;

IntPtr pInput = IntPtr.Zero;

i nt cbOutput = 0;

IntPtr pOutBuffer = new IntPtr();

int nRet = X MFuncEx( cbInput,pInput,ref cbOutput,ref pOutBuffer,IntPtr.Zero );

Marshal.FreeHGlobal(pOutBuffer);

通过把dll中的内存传递出来,Marshal进行内存释放。这样的话,内存声明与释放分开,不是一种良好的编程风格,使用时需谨慎。

5、 未通过测试的方案

C++中增加一个API:int WINAPI XMFuncEx(DWORD cbInput,BYTE* pInput,DWORD *pcbOutput, wchar_t ** pOutBuffer , IRAPIStream * pStream )

{

BYTE *pbtOutput = NULL;

int nRet = XMFunc(cbInput,pInput,pcbOutput,&pbtOutput,NULL);

if (pbtOutput)

{

  wsprintf(*pOutBuffer, TEXT( %s ), (LPCTSTR)pbtOutput);

  LocalFree( pbtOut ) ;

}

return nRet;

}

C#中声明: [ DllImport ( "// XMDLL .dll" , CharSet = CharSet . Unicode , SetLastError = true )]

public static extern int XMFunc(int cbInput, IntPtr pInput, ref int pcbOutput,ref string pOutBuffer,IntPtr pStream);

调用:

i nt cbInput = 0;

IntPtr pInput = IntPtr.Zero;

i nt cbOutput = 0;

String pOutBuffer = “”

i nt nRet = XMFunc(cbInput,pInput,ref cbOutput,ref pOutBuffer,IntPtr.Zero);

随后 System.Diagnostics.Debug.WriteLine(pOutBuffer); 打印完后就会链接断开,退出。

6、 结论

C++中定义的类型可以使用C#中 对应的类型进行替代声明,常用类型对应关系参考其他相关资料,本文不再祥述。如果遇到C++指针,C#中可以使用ref用来按址传递或接收返回。总之,本文只是提供C#和C++调用初探,像结构的传入与传出将在后续中作进一步探讨。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值