C#调用C++的DLL的解决方案
2010-09-15 22:36
495 查看
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++调用初探,像结构的传入与传出将在后续中作进一步探讨。
引言
为了缩短界面开发成本,加上.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++调用初探,像结构的传入与传出将在后续中作进一步探讨。
相关文章推荐
- 关于c#调用c++ dll 的一些问题和解决方案
- c#调用C++ dll 报未将对象引用到设置对象的实例 的解决方案
- c#调用C++ dll 报未将对象引用到设置对象的实例 的解决方案
- C#调用C++编写的COM DLL封装库的问题解决方案
- Unity C# 调用 C++ DLL 并在 DLL 中调用 C# 的回调函数
- C# 调用C++ DLL 的类型转换(转载版)
- C++调用c# dll
- C#调用C++ dll的两种方法
- C#调用C++程序编写的dll
- C#调用C++Dll封装时遇到的一系列问题【转】
- C#调用C++编写的dll
- C++如何调用C#开发的dll
- 在C#工程中调用C++的DLL
- C#调用C++写的dll 函数传递参数问题,请有经验的人详细描述
- C#调用C++DLL传递结构体数组的终极解决方案
- C#程序调用C++写的dll传递string出现bad ptr
- C++调用C#的DLL详解
- C#调用dll(C++(Win32))时的类型转换总结(转)
- C#调用C++DLL
- c#调用C++的DLL的所有数据类型转换