受欢迎的博客标签

VS2019 C++程序生成dll文件

Published

1.Types of DLLs

C++生的DLL,按是否托管维度,可以分为两大类:

1、C++创建的非托管dll库:需要用静态方法调用;非托管模式从功能上来说,只支持函数调用,直接调用C++类库中的公共方法,在被导出的函数前面一定要添加额extern “C来指明导出函数的时候使用C语言方式编译和链接的,这样保证函数定义的名字相同,否则如果默认按C++方式导出,那个函数名字就会变得乱七八糟,别人的程序就无法找到入口点了。
2、C++ 使用CLR创建的托管dll库,生成托管C++dll库

1.1 非托管C++dll库

非托管C++dll库往下细分,vs C++ 可以生成几种形式的类库,不同的类库对应不同的调用方式。

1.vs c++COM方式标准的DLL类库(unmanaged):dll只包含了函数的集合和函数入口点。对外暴露多个函数,供外部程序调用。

   使用api标准,可被任何程序调用。包含了函数所在的DLL文件和文件中函数位置的信息(入口),代码由运行时加载在进程空间中的DLL提供,称为动态链接库dynamic link library.dll是运行时用到的。

C#调用C++编写的DLL函数各种参数传递问题

2.vs c++ 将一个class写成DLL(unmanaged),导出整个类:导出的是整个class。

vs c++ 将一个class写成DLL,导出整个类

C#调用C++导出dll整个类的一个实例

3.MFC的DLL类库(unmanaged):

1.2 托管C++dll库

4.CLR DLL类库(managed):

VS C# 调用C++ CLR dll 混合编程步骤

2.非托管C++dll库的另外一种存在形式

5.标准的LIB类库:

   静态类库,可被任何程序调用。包含函数代码本身,在编译时直接将代码加入程序当中,称为静态链接库static link library.lib是编译时用到的.

Create a C++ DLL (Unmanaged)

Build (Make the DLLs)

Create a C# Project (Managed)

Copy the DLLs to your C# Project

Using the DLL 

 

1.新建一个产生dll的工程-只生成dll文件

DllMain介绍

DllMain:跟exe有个main或者WinMain入口函数一样,DLL也有一个入口函数,就是DllMain.虽然DLL不能自己运行,可是Windows在加载DLL的时候,需要一个入口函数,就如同EXE的main一样,否则系统无法引用DLL。所以根据编写规范,Windows必须查找并执行DLL里的一个函数DllMain作为加载DLL的依据,这个函数不作为API导出,而是内部函数。

 

2.新建一个调用dll的工程

 

Under Configuration Properties, select General, and in the dropdown next to Configuration Type, select Dynamic Library (.dll). Select Apply, and then select OK.

mixed modeset as native dll

This is a complete step, you can refer to it.

see:https://social.msdn.microsoft.com/Forums/en-US/f9bae394-8d48-4142-b979-3c6d76755c34/how-to-use-a-c-dll-in-a-c-project

新建src

将项目移动到src

删除 .vs

将方案另存为 ->根目录

 

分别添加头文件和cpp文件,不要直接添加类。

 

Tutorial: Debug C# and C++ in the same debugging session(c#调式 标准的DLL)

由于C#编绎出来的DLL不是计算机所能直接识别的二进制指令码,需要CLR进行再解释,说到这,我想有些朋友应该知道C#项目需要引用C++编写的DLL时,可以直接引用DLLMPORT来实现调用。而反向的话,C++项目却不能简单靠引用来使用C#编写的DLL。由于C++项目默认配置是没有公共语言运行支持的,因此我们需要更改一些配置,来实现C++项目对C#编写DLL的调用。

 

C#调用C++的dll总归可以有两种方法:

很多时候在项目中需要通过C++调用C#的dll,或者反过来调用。首先明白一个前提:C#是托管型代码。C++是非托管型代码。
托管型代码的对象在托管堆上分配内存,创建的对象由虚拟机托管。(C# )
非托管型代码对象有实际的内存地址,创建的对象必须自己来管理和释放。(C++)

1、非托管C++创建的dll库,需要用静态方法调用;

2、直接使用CLR,生成托管C++dll库。

 

C++、C#交互有三种方式:

1 COM,C# app with C++ libs(C#主 C++从), 在C++这边声明参数的时候,BYTE就是C#的byte,BSTR就是C#的string,想做出参就加*,BYTE*就是C#的ref byte,BSTR* 就是 ref string,但是如果要传byte[]就麻烦了,千万别琢磨着转成string用BSTR传,怎么都不对,只有用BitConverter两个字节两个字节的转在C++这边才能保持正确,但是太慢了,转几M的东西要几十分钟,所以果断VARIANT,在C#端会翻译成object,用C#Marshal分配一段unmanaged的内存,用IntPtr直接传过来就好了,C++端会看到参数类型是VT_INT,直接用VARIANT里INT就是地址,又快又方便。

write COM visible interface and classes in C++ and expose them through COM

import a type library in C#

 

2 P-INVOKE,参数比较简单,直接上网搜一下C++和C#变量对应表就好了,很多,这里和COM有一点不同,比如BYTE*会直接翻译为IntPtr,方便很多。(对于是用COM还是P-INVOKE,见仁见智吧)。

c#

using System;
using System.Runtime.InteropServices;

public class Program
{
    // Import user32.dll (containing the function we need) and define
    // the method corresponding to the native function.
    [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern int MessageBox(IntPtr hWnd, string lpText, string lpCaption, uint uType);

    public static void Main(string[] args)
    {
        // Invoke the function as a regular managed method.
        MessageBox(IntPtr.Zero, "Command-line message box", "Attention!", 0);
    }
}

Platform Invoke (P/Invoke)

 

3 C++/CLI,没什么好说的了,直接Marshal转换各种类型就OK了,唯一麻烦的就是String转换的时候只能用char* 不能用const char*

 

 create a c++ CLR Class Library (.NET Core) project

Create a simple managed (.NET Core) project

Add References c++ CLR Class Library (.NET Core) project

this simple managed (.NET Core) project  app to call the DLL

 

C++和C#混合编程,一个C#调用C++生成的DLL

C++/CLI projects targeting .NET Core 3.x

NET Programming with C++/CLI (Visual C++)

c++和c#数据类型转换(C++与C#的基本类型对照)

//C#调用C++的DLL搜集整理的所有数据类型转换方式
//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++: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 = 数组大小)] public string 数组名; ushort
//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
//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

 

C++生成dll示举例

https://mariusbancila.ro/blog/2019/12/18/cpp-cli-projects-targeting-net-core-3-x/

What is a DLL?

Create C/C++ DLLs in Visual Studio