dll教程1如何编写dll⼀步⼀步,全部可⾏
我们需要学会使⽤dll是为了模块化编程,这点⾮常好,⽽编译调⽤dll我们需要解决如下的问题:
1,如何声明dll中的函数及⽂件
2,如何在应⽤程序中调⽤dll
在如下的⽂章中,这两个问题的语法都能够得到解决
在⼤学⼤⼀的时候学的是C,然后后来⼤⼆的时候专业⼜开了C++这个课程,然后再后来⾃⼰⼜⾃学了⼀点VC++,⼤三的时候也试着编写过⼀个MFC的最简单的窗⼝程序。到⼤四的时候,⾃⼰⼜做了⼀个GIS的项⽬,是⽤C#.NET来编写的,然后发现C#上⼿好容易,⽽且还⼤部分语法规则都沿⽤了C,C++的习惯,于是觉得C++实在是没有⼀点优势可⾔啊。但这个暑假的实习经历⼜改变了我的观点:C++在写窗⼝程序虽然⿇烦,但是却什么能做,⽽且对⽐C#来说,对运⾏环境的要求不⾼,不⽤像C#程序在安装之前还要安装100M多的运⾏.NET环境。C++和C#各有优缺,⽬前我对它们俩的定位是:C++⽤来写⼀些底层的程序,⽐如驱动,或者是⼀些算法类型的函数接⼝,然后⽤C#来调⽤这些接⼝并进⾏界⾯设计。如何函数的实现跨语⾔呢?显然DLL是个很重要的内容,故在此对VC++的DLL模块进⾏介绍。
1 ⽤VC创建DLL动态连接库
1.1 创建dll项⽬
然后选择“⼀个空的dll⼯程”,然后点击“确定”便完成了“创建dll项⽬”的流程。
1.2 为dll项⽬编写源⽂件
新建两个⽂件:dllDemo.h, dllDemo.cpp
在头⽂件”dllDemo.h”中声明三个接⼝函数:
extern "C" _declspec(dllexport) int Sum(int a,int b);//加法函数。extern "C" _declspec(dllexport) int Max(int a, int b);//取较⼤值函数extern "C"
_declspec(dllexport) int Min(int a, int b);//取较⼩值函数
然后在“dllDemo.cpp”⽂件中实现三个接⼝函数:
#include " dllDemo.h "
extern " C " _declspec(dllexport) int Sum( int a, int b)
{
return a + b;
}
extern " C " _declspec(dllexport) int Max( int a, int b)
{
if (a >= b) return a;
else
return b;
}
extern " C " _declspec(dllexport) int Min( int a, int b)
if (a >= b) return b;
else
writeline教程return a;
}
1.3 ⽣成dll⽂件
编译源⽂件,如果没有出现错误提⽰,那么,在项⽬⽂件根⽬录的Debug⽂件夹内会⽣成⼀个dll⽂件“dllDemo.dll”。
2 DLL调⽤
2.1 ⽤C++调⽤显式链接
新建⼀个Win32的控制台程序进⾏显式调⽤:
1. 新建“dllConsoleEvident”的Win32控制台程序项⽬
2. 新建cpp⽂件“dllConsoleEvident.cpp”
3. 将在第⼀节中,在Debug⽬录下编译⽣成的“dllDemo.dll”(显式调⽤时只需要这⼀个⽂件就够了)⽂件复制
到“dllConsoleEvident”项⽬下的Debug⽂件夹根⽬录下
4. 在“dllConsoleEvident.cpp”⽂件中编写以下代码对dll中的函数进⾏显式调⽤
//
// 动态加载DLL⽂件
#include < iostream.h >
#include < windows.h >
void main( void )
{
typedef int ( * pMax)( int a, int b); // 函数指针
typedef int ( * pMin)( int a, int b);
pMax Max = NULL;
pMin Min = NULL;
HINSTANCE hDLL;
hDLL = LoadLibrary( " MyDll.dll " ); // 加载动态链接库MyDll.dll⽂件;
Max = (pMax)GetProcAddress(hDLL, " Max " );
Min = (pMin)GetProcAddress(hDLL, " Min " );
if (Max) // 如果取出函数成功,则执⾏下⾯的语句
{
int A = Max( 5 , 8 );
cout << " ⽐较的结果为 " << A;
}
if (Min)
int B = Min( 5 , 8 );
cout << " ⽐较的结果为 " << B;
}
FreeLibrary(hDLL); // 卸载MyDll.dll⽂件;
}
2.2 ⽤C++隐式链接(Win32控制台程序)
新建⼀个Win32控制台程序演⽰静态调⽤
1. 利⽤向导新建“dllConsoleStaticDemo”的空⼯程
2. 将“dllDemo.dll”和“dllDemo.lib”⽂件复制到Debug⽬录下,并在项⽬中包含“dllDemo.lib”⽂件(或者),否则会出现dll函数不到的连接错误
3. 新建“dllConsoleStaticDemo.cpp”⽂件,并写⼊如下代码:
extern " C " _declspec(dllimport) int Sum( int a, int b);
extern " C " _declspec(dllimport) int Max( int a, int b);
extern " C " _declspec(dllimport) int Min( int a, int b);
#include < iostream.h >
void main()
{
int c = Sum( 4 , 5 );
c = Max( 5 , 6 );
c = Min( 5 , 6 );
cout << " Hello,dllConsoleTest~! " ;
}
4.通过断点,可以看到dll函数调⽤成功
这种⽅式的静态调⽤的特点是:在程序⼀开始执⾏的时候,就将dll⽂件全部加载到程序中,不会释放。
2.3 ⽤C++隐式链接(MFC窗⼝程序)
新建⼀个MFC基本对话框窗⼝程序进⾏调⽤:
1. 利⽤向导建⽴⼀个MFC基本对话框
2. 将“dllDemo.dll”和”dllDemo.lib”⽂件复制到本项⽬的Debug⽬录下,在VC⼯作空间的⽂件视图下⾯将”dllDemo.lib”添加到项⽬中
3. 在“dllMfcDemoDlg.h”头⽂件中的前⾯对来⾃外部的dll函数进⾏声明
// dllMfcDemoDlg.h : header file
//
#if !defined(AFX_DLLMFCDEMODLG_H__E358B876_D188_48FD_8D83_794309C885A9__INCLU
DED_) #define AFX_DLLMFCDEMODLG_H__E358B876_D188_48FD_8D83_794309C885A9__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
/// //
// CDllMfcDemoDlg dialog
extern " C " _declspec(dllimport) int Sum( int a, int b);
extern " C " _declspec(dllimport) int Max( int a, int b);
extern " C " _declspec(dllimport) int Min( int a, int b);
……
4.在窗体界⾯上,双击“确定”按钮,进⼊到OnOk()的事件响应函数体,编写调⽤代码:
void CDllMfcDemoDlg::OnOK()
{
// TODO: Add extra validation here
int c = Sum( 4 , 5 );
c = Max( 5 , 6 );
c = Min( 5 , 6 );
CDialog::OnOK();
}
通过设置断点单步运⾏就可以看到dll⽂件中的函数已经被成功调⽤了。
2.4 ⽤C#跨语⾔调⽤
C#控制台程序调⽤VC++建⽴⼀个dll:
1. ⽤Visual Studio建⽴⼀个控制台程序
2. 将“dllDemo.dll”⽂件复制到项⽬的Debug⽬录下⾯
3. 在“Program.cs”中编写如下代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices; // 引⼊dll⽂件中的函数
namespace ConsoleDllDemo
{
class Program
{
// 引⼊dll⽂件中的函数
[DllImport( " dllDemo.dll " )]
private static extern int Sum( int a, int b);
[DllImport( " dllDemo.dll " )]
private static extern int Max( int a, int b);
[DllImport( " dllDemo.dll " )]
private static extern int Min( int a, int b);
static void Main( string [] args)
{
int a = Sum( 3 , 5 );
Console.WriteLine(a);
Console.WriteLine(Max( 5 , 10 ));
Console.WriteLine(Min( 12 , 25 ));
Console.ReadKey(); // 要按键才退出。
}
}
}
然后断点单步运⾏,便可以看到调⽤函数的结果了。
关于DLL的调⽤的更详细内容可以参考另外⼀些⽂章:
3 dll调试⽅法
在建⽴了dll项⽬后,并写好相应的实现代码,点击“运⾏”,会弹出现在的对话框:
然后浏览,到⼀个调⽤了此dll⽂件的执⾏⽂件“*.exe”⽂件,然后就可以对dll⽂件进⾏断点调试了。
这个“*.exe”⽂件可以是任何平台的,C++也可以,C也可以,C#也可以,只要这个执⾏⽂件调⽤了dll⽂件中的函数即可。
如果想更换调试的“*.exe”⽂件,可以在“⼯程-》设置”对话框中的“调试”选项卡进⾏设置,浏览到⽤户需要的“*.exe”⽂件
说明:以VC++环境中调⽤此dll为例,运⾏dllDemo项⽬,然后会调⽤“*.exe”⽂件,如果此exe⽂件含有源⽂件,⽽且刚好在源⽂件的Debug⽬录下⾯,那么,可以同时在exe⽂件的源⽂件中设置断点,进⾏dll和调⽤dll两个程序的联调。(好像跨语⾔调⽤的时候不能进⾏联调,笔者只在C++互相调⽤的时候联调成功过,但C#调⽤的时候没有联调成功,这个问题有待解决)
4. DLL返回数据类型探究
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论