C#与C++的混合编程 之三 C++与C#的数据传递与类型转换
一、数据传递方法
1.基本数据类型的传递
函数参数和返回值可以是C#和C++的各种基本数据类型,如int, float, double, char(注意不是char*)等。
示例:
C#代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
using
System; using
System.Text; using
System.Runtime.InteropServices; class
Program { [DllImport( @"E:\Projects\testdll\debug\testdll.dll" )] public static
extern int
testfunc( int a, float
b, double
c, char d); static void
Main( string [] args) { int a = 1; float b = 12; double c = 12.34; char d =
'A' ; testfunc(a,b,c,d); Console.ReadKey(); } } |
C++代码:
1
2
3
4
5
6
7
8
9
10
11
12
|
<pre class = "brush:cpp" >#include <iostream> using namespace
std; extern "C" { _declspec( dllexport ) int
__stdcall testfunc( int a, float
b, double
c, char d) { cout<<a<< ", " <<b<< ", " <<c<< ",
" <<d<<endl; return 0; } } </pre> |
2.向DLL传入字符串
C#中使用string定义字符串,将字符串对象名传给DLL。
注意:在DLL中更改字符串的值,C#中的值也会改变。
缺点:无法改变字符串的长度,建议使用第3种方法。
C#代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
using
System; using
System.Text; using
System.Runtime.InteropServices; class
Program { [DllImport( @"E:\Projects\testdll\debug\testdll.dll" )] public static
extern int
testfunc( string a); static void
Main( string [] args) { string a= "Hello World!" ; testfunc(a); Console.ReadKey(); } } |
C++代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#include <iostream> using namespace
std; extern "C" { _declspec( dllexport ) int
__stdcall testfunc( char * astr) { cout<<astr<<endl; *astr= 'A' ; //更改字符串的数据 cout<<astr<<endl; return 0; } } |
3.DLL传出字符串
C#中使用StringBuilder对象创建变长数组,并设置StringBuilder的Capacity为数组最大长度。将此对象名传递给DLL,使用char*接收。
C#代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
using
System; using
System.Text; using
System.Runtime.InteropServices; class
Program { [DllImport( @"E:\Projects\testdll\debug\testdll.dll" )] public static
extern int
testfunc(StringBuilder abuf); static void
Main( string [] args) { StringBuilder abuf= new StringBuilder(); abuf.Capacity = 100; //设置字符串最大长度 testfunc(abuf); Console.ReadKey(); } } |
C++代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <iostream> using namespace
std; extern "C" { _declspec( dllexport ) int
__stdcall testfunc( char * astr) { *astr++= 'a' ; *astr++= 'b' ; //C#中abuf随astr改变 *astr= '\0' ; return 0; } } |
4.DLL传递结构体(需要在C#中重新定义,不推荐使用)
C#中使用StructLayout重新定义需要使用的结构体。
注意:在DLL改变结构体成员的值,C#中随之改变。
C#代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
using
System; using
System.Text; using
System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential)] public
struct Point { public double
x; public double
y; } class Program { [DllImport( @"E:\Projects\testdll\debug\testdll.dll" )] public static
extern int
testfunc(Point p); static void
Main( string [] args) { Point p; p.x = 12.34; p.y = 43.21; testfunc(p); Console.ReadKey(); } } |
C++代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#include <iostream> using namespace
std; struct Point { double x; double y; }; extern "C" { _declspec( dllexport ) int
__stdcall testfunc(Point p) { cout<<p.x<< ", " <<p.y<<endl; return 0; } } |
5.从C++传出字符串
C++代码:
#ifndef RGB_IHS_C_ADAPTER
#define RGB_IHS_C_ADAPTER
typedef char * (__stdcall* StringHelperCallback)(const char *);
static StringHelperCallback g_csharp_string_callback = NULL;
extern "C" __declspec(dllexport) void RegisterStringCallback(StringHelperCallback callback) {
g_csharp_string_callback = callback;
}
extern "C" __declspec(dllexport) int ExcuteAlgo(const TCHAR* m_strRealpath,
const TCHAR* m_strClassPath,
const char* m_tsReal ,
const char* m_tsclass,
const TCHAR* m_tsRealClassName,
const char*m_tsClassName,
char** fileInfo,/*数据返回,指向C#用委托开辟的内存*/
SysAlgo::stAlgoErr* err,
pProgressFunc pProg,void* pParams);
#endif
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace AccuracyAnalysis
{
public delegate int ProgressCallback(double dbPos, string pszMessage, IntPtr pArgs);
public struct stAtomDataInfo
{
public string m_strRealpath;
public string m_strClassPath;
public string m_tsReal;
public string m_tsclass;
public string m_tsRealClassName;
public string m_tsClassName;
public string fileInfo;
public stAlgoErr err;
public ProgressCallback pProg;
public IntPtr pParams;
}
public struct stAlgoErr
{
private int m_ErrCode;
private string m_ErrMsg;
public stAlgoErr(int errCode, string errMsg)
{
m_ErrCode = errCode;
m_ErrMsg = errMsg;
}
public int GetErrCode()
{
return m_ErrCode;
}
public string GetErrMsg()
{
return m_ErrMsg;
}
public void SetErrCodeAndMsg(int errCode, string errMsg)
{
m_ErrCode = errCode;
m_ErrMsg = errMsg;
}
}
class Algo
{
#region 本段代码可放在其他位置,但保证系统启动后能初始化
static protected StringHelper swigStringHelper = new StringHelper();
protected class StringHelper
{
public delegate string StringDelegate(string message);
static StringDelegate stringDelegate = new StringDelegate(CreateString);
[DllImport("ImgClassPostPA.dll", EntryPoint = "RegisterStringCallback", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern void RegisterStringCallback(StringDelegate stringDelegate);
static string CreateString(string cString)
{
return cString;
}
static StringHelper()
{
RegisterStringCallback(stringDelegate);
}
}
#endregion
#region 算法调用
[DllImport("ImgClassPostPA.dll", EntryPoint = "ExcuteAlgo", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int ExcuteAlgo(string m_strRealpath, string m_strClassPath, string m_tsReal, string m_tsclass,
string m_tsRealClassName, string m_tsClassName, ref string fileInfo, ref stAlgoErr err, ProgressCallback pProg, IntPtr pParams);
#endregion
}
}
二、C++与C#的基本类型对照:
//c++:HANDLE(void *) ---- c#:System.IntPtr
//c++:Byte(unsigned char) ---- c#:System.Byte
//c++:SHORT(short) ---- c#:System.Int16
//c++:WORD(unsigned short) --- c#:System.UInt16
//c++:INT(int) ---- c#:System.Int16
//c++:INT(int) ---- c#:System.Int32
//c++:UINT(unsigned int) ---- c#:System.UInt16
//c++:UINT(unsigned int) ---- c#:System.UInt32
//c++:LONG(long) ---- c#:System.Int32
//c++:ULONG(unsigned long) -- c#:System.UInt32
//c++:DWORD(unsigned long) -- c#:System.UInt32
//c++:DECIMAL ---- c#:System.Decimal
//c++:BOOL(long) ---- c#:System.Boolean
//c++:CHAR(char) ---- c#:System.Char
//c++:LPSTR(char *) ---- c#:System.String
//c++:LPWSTR(wchar_t *) ---- c#:System.String
//c++:LPCSTR(const char *) --- c#:System.String
//c++:LPCWSTR(const wchar_t *) --- c#:System.String
//c++:PCAHR(char *) ---- c#:System.String
//c++:BSTR ---- c#:System.String
//c++:FLOAT(float) ---- c#:System.Single
//c++:DOUBLE(double) ---- c#:System.Double
//c++:VARIANT ---- c#:System.Object
//c++:PBYTE(byte *) ---- c#:System.Byte[]
//c++:BSTR ---- c#:StringBuilder
//c++:LPCTSTR ---- c#:StringBuilder
//c++:LPCTSTR ---- c#:string
//c++:LPTSTR ---- c#:[MarshalAs(UnmanagedType.LPTStr)] string
//c++:LPTSTR ---- c#:StringBuilder
//c++:LPCWSTR ---- c#:IntPtr
//c++:BOOL ---- c#:bool
//c++:HMODULE ---- c#:IntPtr
//c++:HINSTANCE ---- c#:IntPtr
//c++:结构体 ---- c#:public struct 结构体{};
//c++:结构体 **变量名 ---- c#:out 变量名
//C#中提前申明一个结构体实例化后的变量名
//c++:结构体 &变量名 ---- c#:ref 结构体 变量名
//c++:WORD ---- c#:ushort
//c++:DWORD ---- c#:uint
//c++:DWORD ---- c#:int
//c++:UCHAR ---- c#:int
//c++:UCHAR ---- c#:byte
//c++:UCHAR* ---- c#:string
//c++:UCHAR* ---- c#:IntPtr
//c++:GUID ---- c#:Guid
//c++:Handle ---- c#:IntPtr
//c++:HWND ---- c#:IntPtr
//c++:DWORD ---- c#:int
//c++:COLORREF ---- c#:uint
//c++:unsigned char ---- c#:byte
//c++:unsigned char * ---- c#:ref byte
//c++:unsigned char * ---- c#:[MarshalAs(UnmanagedType.LPArray)] byte[]
//c++:unsigned char * ---- c#:[MarshalAs(UnmanagedType.LPArray)] Intptr
//c++:unsigned char & ---- c#:ref byte
//c++:unsigned char 变量名 ---- c#:byte 变量名
//c++:unsigned short 变量名 ---- c#:ushort 变量名
//c++:unsigned int 变量名 ---- c#:uint 变量名
//c++:unsigned long 变量名 ---- c#:ulong 变量名
//c++:char 变量名 ---- c#:byte 变量名
//c++中一个字符用一个字节表示,c#中一个字符用两个字节
表示
//c++:char 数组名[数组大小] ---- c#:MarshalAs(UnmanagedType.ByValTStr, SizeConst
= 数组大小)]
//c++:char * ---- c#:string
//c++:char * ---- c#:StringBuilder
//c++:char *变量名 ---- c#:ref string 变量名
//c++:char *输入变量名 ---- c#:string 输入变量名
//c++:char *输出变量名 ---- c#:[MarshalAs(UnmanagedType.LPStr)]
StringBuilder 输出变量名
//c++:char ** ---- c#:string
//c++:char **变量名 ---- c#:ref string 变量名
//c++:const char * ---- c#:string
//c++:char[] ---- c#:string
//c++:char 变量名[数组大小] ---- c#:[MarshalAs
(UnmanagedType.ByValTStr,SizeConst=数组大小)]
public string 变量名;
//c++:struct 结构体名 *变量名 ---- c#:ref 结构体名
变量名
//c++:委托 变量名 ---- c#:委托 变量名
//c++:int ---- c#:int
//c++:int ---- c#:ref int
//c++:int & ---- c#:ref int
//c++:int * ---- c#:ref int
//C#中调用前需定义int 变量名 = 0;
//c++:*int ---- c#:IntPtr
//c++:int32 PIPTR * ---- c#:int32[]
//c++:float PIPTR * ---- c#:float[]
//c++:double** 数组名 ---- c#:ref double 数
组名
//c++:double*[] 数组名 ---- c#:ref double 数
组名
//c++:long ---- c#:int
//c++:ulong ---- c#:int
//c++:UINT8 * ---- c#:ref byte
//C#中调用前需定义byte 变量名 = new byte();
//c++:handle ---- c#:IntPtr
//c++:hwnd ---- c#:IntPtr
//c++:void * ---- c#:IntPtr
//c++:void * user_obj_param ---- c#:IntPtr user_obj_param
//c++:void * 对象名称 ---- c#:([MarshalAs(UnmanagedType.AsAny)]Object 对象
名称
//c++:char,INT8,SBYTE,CHAR -- c#:System.SByte
//c++:short, short int, INT16, SHORT
---- c#:System.Int16
//c++:int, long, long int,INT32, LONG32, BOOL , INT ---- c#:System.Int32
//c++:__int64,INT64,LONGLONG -- c#:System.Int64
//c++:unsigned char, UINT8, UCHAR , BYTE ---- c#:System.Byte
//c++:unsigned short, UINT16, USHORT, WORD,
ATOM, WCHAR , __wchar_t ---- c#:System.UInt16
//c++:unsigned, unsigned int, UINT32, ULONG32,
DWORD32, ULONG, DWORD, UINT
---- c#:System.UInt32
//c++:unsigned __int64, UINT64, DWORDLONG,
ULONGLONG
---- c#:System.UInt64
//c++:float,FLOAT -- c#:System.Single
//c++:double, long double, DOUBLE
---- c#:System.Double
//Win32 Types ---- CLR Type
//Struct需要在C#里重新定义一个Struct
//CallBack回调函数需要封装在一个委托里,delegate
static extern int FunCallBack(string str);
//unsigned char** ppImage替换成IntPtr ppImage
//int& nWidth替换成ref int nWidth
//int*, int&, 则都可用 ref int 对应
//双针指类型参数,可以用 ref IntPtr
//函数指针使用c++: typedef double (*fun_type1)
(double); 对应 c#:public delegate double fun_type1
(double);
//char* 的操作c++: char*; 对应 c#:StringBuilder;
//c#中使用指针:在需要使用指针的地方 加 unsafe
//unsigned char对应public byte