您的位置:首页 > 编程语言 > C语言/C++

C#调用C++DLL

2017-02-21 10:19 218 查看
   在合作开发时,C#时常需要调用C++DLL。研究了一下C#,发现其强大简洁,
在跨语言调用方面封装的很彻底,提供了强大的API与之交互.这点比JNA方便多了. Java与C#都只能调用C格式导出动态库,因为C数据类型比较单一,容易映射. 两者都是在本地端提供一套与之映射的C#/java描述接口,通过底层处理这种映射关系达到调用的目的.

1、调用例子(例子中提供了传值调用和传址调用两种方法):

C++代码(C++生成动态库DLL.dll):

Lib.h

//文件:lib.h
#pragma once

#include <string>
using namespace std;

#define JNAAPI extern "C" __declspec(dllexport) // C方式导出函数

typedef struct CARDINFO
{
int majorVersion;
int minorVersion;
int cardType;
char szDescribe[128];
};

// 1. 获取版本信息(传递结构体指针)
JNAAPI bool GetVersionPtr(CARDINFO *info);
// 2.获取版本信息(传递结构体引用)
JNAAPI bool GetVersionRef(CARDINFO &info);


Lib.cpp

#include "stdafx.h"
#include "lib.h"
#include <stdlib.h>

using namespace std;

// 1. 获取版本信息(传递结构体指针)
bool GetVersionPtr(CARDINFO *info)
{
info->majorVersion = 1;
info->minorVersion = 22;
info->cardType = 3;
memcpy(info->szDescribe, "hello world", 128);

return true;
}

// 2.获取版本信息(传递结构体引用)
bool GetVersionRef(CARDINFO &info)
{
info.majorVersion = 1;
info.minorVersion = 22;
info.cardType = 3;
memcpy(info.szDescribe, "hello world", 128);

return true;
}


C#代码(C++生成动态库DLL.dll):

class CCommand
{
const string dllpathfile = "..\\..\\..\\..\\Lib\\DLL.dll";

// CARDINFO定义
[StructLayout(LayoutKind.Sequential)]
public struct CARDINFO
{
public int majorVersion;
public int minorVersion;
public int cardType;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string szDescribe;
}

[DllImport(dllpathfile, EntryPoint = "GetVersionPtr")]
public static extern bool GetVersionPtr(ref CARDINFO info);

[DllImport(dllpathfile, EntryPoint = "GetVersionRef")]
public static extern bool GetVersionRef(ref CARDINFO info);
}

调用:


//C#调用C++库
CCommand.CARDINFO cardInfo = new CCommand.CARDINFO();
CCommand.GetVersionPtr(ref cardInfo);






2、类型转换说明:

类型对照:

C++类型

C#类型

BSTR

StringBuilder

LPCTSTR

StringBuilder

LPCWSTR

IntPtr

handle

IntPtr

hwnd

IntPtr

char *

string

int *

ref int

int &

ref int

void *

IntPtr

unsigned char *

ref byte

CLR Type

Win32 Types

System.SByte

char, INT8, SBYTE, CHAR

System.Int16

short, short int, INT16, SHORT

System.Int32

int, long, long int, INT32, LONG32, BOOL , INT

System.Int64

__int64, INT64, LONGLONG

System.Byte

unsigned char, UINT8, UCHAR , BYTE

System.UInt16

unsigned short, UINT16, USHORT, WORD, ATOM, WCHAR , __wchar_t

System.UInt32

unsigned, unsigned int,

UINT32, ULONG32, DWORD32, ULONG, DWORD, UINT

System.UInt64

unsigned __int64,

UINT64, DWORDLONG, ULONGLONG

System.Single

float, FLOAT

System.Double

double, long double, DOUBLE

注:

C#中类型转换接口:

将string转为IntPtr:

IntPtrSystem.Runtime.InteropServices.Marshal.StringToCoTaskMemAuto(string)

 

将IntPtr转为string:

stringSystem.Runtime.InteropServices.MarshalPtrToStringAuto(IntPtr)

3、代码分析

C#为了用上C++的代码,只好研究下从C# 中调用DLL,首先必须要有一个声明,使用的是DllImport关键字,包含DllImport所在的名字空间

using System.Runtime.InteropServices;
class CCommand
{
conststringdllpathfile ="..\\..\\..\\..\\Lib\\DLL.dll";
[DllImport(dllpathfile, EntryPoint ="GetVersionPtr")]
publicstaticexternboolGetVersionPtr(refCARDINFOinfo);
}


DllImport关键字作用是告诉编译器入口点在哪里,并将打包函数捆绑在这个类中,在类中,直接调用GetVersionPtr,在其他的类中调用CCommand.GetVersionPtr

[DllImport(dllpathfile)]在申明的时候还可以添加几个属性

[DllImport(dllpathfile, EntryPoint="GetVersionPtr ",CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)

]

EntryPoint: 指定要调用的 DLL 入口点。默认入口点名称是托管方法的名称 。

CharSet: 控制名称重整和封送 String 参数的方式 (默认是UNICODE)

CallingConvention指示入口点的函数调用约定(默认WINAPI)

SetLastError 指示被调用方在从属性化方法返回之前是否调用 SetLastError Win32 API 函数 (C#中默认false )
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c# C++ DLL