首页 - 新闻 - vs2010 生成c dll文件_

vs2010 生成c dll文件_

2023-09-17 18:47

一、为什么需要dll

代码复用是提高软件开发 效率的重要途径。一般而言,只要某部分代码具有通用性,就可将它构造成相对独立的功能模块并在之后的项目中重复使用。比较常见的例子是各种应用程序框架, 如ATL、MFC等,它们都以源代码的形式发布。由于这种复用是“源码级别”的,源代码完全暴露给了程序员,因而称之为“白盒复用”。“白盒复用”的缺点 比较多,总结起来有4点。

暴露了源代码;容易与程序员的“普通”代码发生命名冲突;多份拷贝,造成存储浪费;更新功能模块比较困难。

实际上,以上4点概括起来就是“暴露的源代码”造成“代码严重耦合”。为了弥补这些不足,就提出了“二进制级别”的代码复用。使用二进制级别的代码复用一定程度上隐藏了源代码,对于缓解代码耦合现象起到了一定的作用。这样的复用被称为“黑盒复用”。

在Windows操作系 统中有两种可执行文件,其后缀名分别为.exe和.dll。它们的区别在于,.exe文件可被独立的装载于内存中运行;.dll文件却不能,它只能被其它 进程调用。然而无论什么格式,它们都是二进制文件。上面说到的“二进制级别”的代码复用,可以使用.dll来实现。

与白盒复用相 比,.dll很大程度上弥补了上述4大缺陷。.dll是二进制文件,因此隐藏了源代码;如果采用“显式调用”(后边将会提到),一般不会发生命名冲突;由 于.dll是动态链接到应用程序中去的,它并不会在链接生成程序时被原原本本拷贝进去;.dll文件相对独立的存在,因此更新功能模块是可行的。

说明:实现“黑盒复用”的途径不只dll一种,静态链接库甚至更高级的COM组件都是。本文只对dll进行讨论。

二、C语言制作dll文件

1. 启动vs2010,?

2.创建dll工程

  a. 文件 -> 新建 -> ?项目 -> win32控制台应用程序 —>?

  b. 输入工程名称, 比如 dll, 点击确定

  c. 点击下一步, 在“应用程序设置界面” 勾选 dll 和空项目, 点击完成按钮

  d. 视图 -> 解决方案资源管理器 ->右键点击头文件, 添加->新建项,这里用dll.h,

  e.?右键点击"源文件",添加->新建项,这里我们添加dll.c,到此dll工程搭建完毕.?

3. dll.h

#ifndef AXLPLUGIN_H

#define AXLPLUGIN_H

/**/

#ifdef _WINDOWS

#define DLL_DECLARE __declspec(dllexport)

#else

#define DLL_DECLARE

#endif

DLL_DECLARE int Min(int a, int b);

/* 把所有的函数声明都列在这里 */

#endif

4. dll.c

#include "dll.h"

#include

/*根据需要添加相应的头文件*/

DLL_DECLARE int Min(int a, int b)

{

if (a >= b)

return b;

else

return a;

}

/* 把所有声明的函数都在这里实现*/

5. 生成dll lib 文件

点击build -> build dll

这样,dll 和 lib 文件就生成了。

5. dll文件的使用

试验证明dll.dll文件要和dll.lib以及dll.h文件一起使用 ?

三 ,在程序中加载dll

新建一个测试用的"Win32应用程序" ?操作:

   ?a.文件->新建->项目->Win32控制台应用程序.

?  ?b.输入工程名称,这里我们用test_dll,点击确定按钮. ?

???????c.点击下一步,在"应用程序设置界面设置"控制台应用程序"和"空项目",点击完成按钮.??

???????d.将工程dll目录里的dll.h/dll.dll/dll.lib拷贝到工程test_dll目录里。??

???????e.视图->解决方案资源管理器,右键点击"头文件",添加->新建项,这里咱们用dll.h??

?????????右键点击"源文件",添加->新建项,这里我们添加test_dll.c,右键点击“资源文件”,??

?????????添加->"现有项",选择dll.lib,到此test_dll工程搭建完毕. ??

  3.??编辑test_dll.c文件,内容如下?

#include "dll.h"

#include

int main()

{

printf("Min(2, 4) = %d\n", Min(2, 4));

printf("Min(5, 2) = %d\n", Min(5, 2));

return 0;

}

四,dll和test_dll工程的目录结构 ?

../test_dll/

│ test_dll.sdf

│ test_dll.sln

│ test_dll_dir.txt

├─Debug

│ test_dll.exe

│ test_dll.ilk

│ test_dll.pdb

├─ipch

│ └─test_dll-eb5063a1

│ test_dll-c06c53e7.ipch

└─test_dll

│ dll.dll

│ dll.h

│ dll.lib

│ test_dll.c

│ test_dll.vcxproj

│ test_dll.vcxproj.filters

│ test_dll.vcxproj.user

└─Debug

cl.command.1.tlog

CL.read.1.tlog

CL.write.1.tlog

link-cvtres.read.1.tlog

link-cvtres.write.1.tlog

link.3004-cvtres.read.1.tlog

link.3004-cvtres.write.1.tlog

link.3004.read.1.tlog

link.3004.write.1.tlog

link.command.1.tlog

link.read.1.tlog

link.write.1.tlog

mt.command.1.tlog

mt.read.1.tlog

mt.write.1.tlog

rc.command.1.tlog

rc.read.1.tlog

rc.write.1.tlog

test_dll.Build.CppClean.log

test_dll.exe.embed.manifest

test_dll.exe.embed.manifest.res

test_dll.exe.intermediate.manifest

test_dll.lastbuildstate

test_dll.log

test_dll.obj

test_dll_manifest.rc

vc100.idb

vc100.pdb

?

转载于:https://www.gsm-guard.net/wangjz/p/4808803.html

1.首先创建生成dll的项目:打开VS2010,两种途经建立dll项目,基于MFC DLL的和基于Win32控制台应用程序的,这里选择基于Win32控制台建立。

a.文件--新建--项目(项目命名为myAPI)--Visual C++ --Win32--选择Win32控制台应用程序;

b.接下来下一步一直到如下图,程序类型选择DLL,如无特殊需要选择空项目完成,项目建立完毕;

2.定义头文件:为项目添加头文件myAPI.h 内部添加如下代码,

#ifndef _DLL_API

#define _DLL_API _declspec(dllexport)

#else

#define _DLL_API _declspec(dllimport)

#endif

_DLL_API int ADD(int a,int b);

内部定义一个ADD()函数接口,如需添加其他函数接口,可以接着继续定义,如

_DLL_API int MINUS(int a,int b);

_DLL_API int otherfunc(int,int,int);

3.定义源文件:为项目添加相应的源文件myAPI.cpp 之后便是在该源文件中对函数进行定义,内部添加如下代码,

#include "myAPI.h"

??

在VS2010上使用C#调用非托管C++生成的DLL文件(图文讲解)

背景?

???? 在项目过程中,有时候你需要调用非C#编写的DLL文件,尤其在使用一些第三方通讯组件的时候,通过C#来开发应用软件时,就需要利用DllImport特性进行方法调用。本篇文章将引导你快速理解这个调用的过程。

步骤

1. 创建一个CSharpInvokeCPP的解决方案:

2. 创建一个C++的动态库项目:

3. 在应用程序设置中,选择“DLL”,其他按照默认选项:

最后点击完成,得到如图所示项目:

????? 我们可以看到这里有一些文件,其中dllmain.cpp作为定义DLL应用程序的入口点,它的作用跟exe文件有个main或者WinMain入口函数是一样的,它就是作为DLL的一个入口函数,实际上它是个可选的文件。它是在静态链接时或动态链接时调用LoadLibrary和FreeLibrary时都会被调用。详细内容可以参考(DllMain详解_许振坪的专栏-CSDN博客_dllmain)。

4. 现在我们打开CSharpInvokeCPP.CPPDemo.cpp文件:

现在我们加入以下内容:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

// CSharpInvokeCPP.CPPDemo.cpp : 定义 DLL 应用程序的导出函数。

//

#include "stdafx.h"

extern

"C"

__declspec

(

dllexport

)

int

Add(

int

x,

int

y)

{

????

return

x + y;

}

extern

"C"

__declspec

(

dllexport

)

int

Sub(

int

x,

int

y)

{

????

return

x - y;

}

extern

"C"

__declspec

(

dllexport

)

int

Multiply(

int

x,

int

y)

{

????

return

x * y;

}

extern

"C"

__declspec

(

dllexport

)

int

Divide(

int

x,

int

y)

{

????

return

x / y;

}

????? extern "C" 包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的;其次,被它修饰的目标是“C”的。而被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。

????? __declspec(dllexport)的目的是为了将对应的函数放入到DLL动态库中。

????? extern "C" __declspec(dllexport)加起来的目的是为了使用DllImport调用非托管C++的DLL文件。因为使用DllImport只能调用由C语言函数做成的DLL。

5. 编译项目程序,最后在Debug目录生成CSharpInvokeCPP.CPPDemo.dll和CSharpInvokeCPP.CPPDemo.lib

我们用反编译工具PE Explorer查看下该DLL里面的方法:

可以发现对外的公共函数上包含这四种“加减乘除”方法。

6. 现在来演示下如何利用C#项目来调用非托管C++的DLL,首先创建C#控制台应用程序:

7. 在CSharpInvokeCSharp.CSharpDemo项目上新建一个CPPDLL类,编写以下代码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

public

class

CPPDLL

{

????

[DllImport(

"CSharpInvokeCPP.CPPDemo.dll"

)]

????

public

static

extern

int

Add(

int

x,

int

y);

????

[DllImport(

"CSharpInvokeCPP.CPPDemo.dll"

)]

????

public

static

extern

int

Sub(

int

x,

int

y);

????

[DllImport(

"CSharpInvokeCPP.CPPDemo.dll"

)]

????

public

static

extern

int

Multiply(

int

x,

int

y);

????

[DllImport(

"CSharpInvokeCPP.CPPDemo.dll"

)]

????

public

static

extern

int

Divide(

int

x,

int

y);

}

DllImport作为C#中对C++的DLL类的导入入口特征,并通过static extern对extern “C”进行对应。

8. 另外,记得把CPPDemo中生成的DLL文件拷贝到CSharpDemo的bin目录下,你也可以通过设置【项目属性】->【配置属性】->【常规】中的输出目录:

这样编译项目后,生成的文件就自动输出到CSharpDemo中了。

9. 然后在Main入口编写测试代码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

static

void

Main(

string

[] args)

{

????

int

result = CPPDLL.Add(10, 20);

????

Console.WriteLine(

"10 + 20 = {0}"

, result);

????

result = CPPDLL.Sub(30, 12);

????

Console.WriteLine(

"30 - 12 = {0}"

, result);

????

result = CPPDLL.Multiply(5, 4);

????

Console.WriteLine(

"5 * 4 = {0}"

, result);

????

result = CPPDLL.Divide(30, 5);

????

Console.WriteLine(

"30 / 5 = {0}"

, result);

????

Console.ReadLine();

}

运行结果:

方法得到调用。

10. 以上的方法只能通过静态方法对于C++中的函数进行调用。那么怎样通过静态方法去调用C++中一个类对象中的方法呢?现在我在CPPDemo项目中添加一个头文件userinfo.h:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

class

UserInfo {

private

:

????

char

* m_Name;

????

int

m_Age;

public

:

????

UserInfo(

char

* name,

int

age)

????

{

????????

m_Name = name;

????????

m_Age = age;

????

}

????

virtual

~UserInfo(){ }

????

int

GetAge() {

return

m_Age; }

????

char

* GetName() {

return

m_Name; }

};

在CSharpInvokeCPP.CPPDemo.cpp中,添加一些代码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

#include "malloc.h"

#include "userinfo.h"

typedef

struct

{

????

char

name[32];

????

int

age;

} User;?

UserInfo* userInfo;

extern

"C"

__declspec

(

dllexport

) User* Create(

char

* name,

int

age)???

{??

????

User* user = (User*)

malloc

(

sizeof

(User));

????

userInfo =

new

UserInfo(name, age);

????

strcpy

(user->name, userInfo->GetName());?

????

user->age = userInfo->GetAge();

????

return

user;

}

这里声明一个结构,包括name和age,这个结构是用于和C#方面的结构作个映射。

注意:代码中的User*是个指针,返回也是一个对象指针,这样做为了防止方法作用域结束后的局部变量的释放。

strcpy是个复制char数组的函数。

11. 在CSharpDemo项目中CPPDLL类中补充代码:

?

1

2

3

4

5

6

7

8

9

10

11

[DllImport(

"CSharpInvokeCPP.CPPDemo.dll"

)]

public

static

extern

IntPtr Create(

string

name,

int

age);

[StructLayout(LayoutKind.Sequential)]

public

struct

User

{

????

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]

????

public

string

Name;

????

public

int

Age;

}

其中这里的结构User就和C++中的User对应。

12. 在Program.cs中补充代码:

?

1

2

3

IntPtr ptr = CPPDLL.Create(

"李平"

, 27);

"#ff0000"

>CPPDLL.User user = (CPPDLL.User)Marshal.PtrToStructure(ptr,

typeof

(CPPDLL.User));

Console.WriteLine(

"Name: {0}, Age: {1}"

, www.gsm-guard.net, user.Age);

注意:红色字体部分,这里结构指针首先转换成IntPtr句柄,然后通过Marshal.PtrToStructrue转换成你所需要的结构。

运行结果:

最后附上我的源代码:CSharpInvokeCPP.rar,希望对大家有所帮助:)

zhuanzi?? ?https://www.gsm-guard.net/liping13599168/archive/2011/03/31/2000320.html