VC++怎样生成DLL

来源:互联网 发布:大数据相关论文 编辑:程序博客网 时间:2024/04/28 16:26

VC++怎样生成DLL 转
---- 在用PowerBuilder开发应用程序时,经常需要调用动态链接库DLL,本文介绍了动态链接库的基本特点,给出了VC++建立DLL以及在PowerBuilder中调用VC++创建的DLL函数的编程实例,实现了通过DLL连接PowerBuilder和VC++编制的不同程序的目的。

一、 DLL概述:
---- 动态链接库(Dynamic-Link Library),简称DLL,是基于Windows程序设计的一个非常重要的组成部分。使用DLL有许多优点:(1)使用DLL的动态连接不是将库代码拷贝,只在程序中记录函数的入口点和接口,在程序执行时才将库代码装入内存,如果有多个程序使用相同的DLL,也只需将DLL在内存中装载一次,节省了内存开销。(2)DLL是基于Windows的程序模块,它不仅包含可执行代码,还可以包含数据,各种资源,扩大了库文件的使用范围。(3)对于一个大型的、不断更新的应用程序,可以将许多重复的功能写成DLL,用主程序调用,这样既减少了开发的工作量,又提高了访问速度。(4)DLL丰富了PowerScript语言的编程能力,可以使用PowerScript函数集之外的函数。例如:用户可能编写图象处理系统来浏览文件并将其存放于数据库,该应用需使用浏览器,但用PowerScript语言未提供做这类工作的函数,为了操纵设备,需要与设备本身环境通信,该环境一般是厂商提供的动态链接库。(5)DLL独立于编程语言,大多数WINDOWS编程环境都允许主程序调用DLL中的函数。即可以用VC++、VB、PowerBuilder、Delphi、汇编语言等建立DLL,然后在不同语言编制的应用程序中调用它。下面用一个实例说明通过DLL实现PowerBuilder程序和VC++程序之间的连接。
二、 VC++创建DLL
---- 在VC++5.0中可以用MFC AppWizard自动生成Win32 DLL和MFC AppWizard DLL,启动VC之后,从File | New菜单项,选择New对话框中的Projects标签,选择新项目为MFC AppWizard(dll),输入工程名pbdll,点击OK按钮,弹出图1-1所示对话框,选择DLL类型为:Regular DLL using shared MFC DLL,然后点击Finish按钮。这样,AppWizard将自动创建一个包含基本要素的DLL框架,接着手工添加代码。
图1-1 (略)自动生成的MFC AppWizard DLL
打开pbdll.cpp文件,添加如下函数:
extern "C" _declspec ( dllexport )
int PASCAL out_num(int x)
{
    int y;
    char msg[30];
    y=x > >2;
    sprintf(msg, "计算结果:%o ! ", y);
    ::MessageBox(NULL, msg, "信息", MB_OK);
    return 0;
}
以上声明了函数out_num(),输入参数为一个整型数,
作移位运算后,用对话框将计算结果显示出来。
接着打开pbdll.def文件,在EXPORTS下输入函数说明
out_num,文件内容如下:
LIBRARY    "pbdll"
DESCRIPTION 'pbdll Windows Dynamic Link Library'

EXPORTS
    ; Explicit exports can go here
    out_num @1
最后编译生成动态链接库pbdll.dll。

三、 在PowerBuilder中调用VC++创建的DLL函数
---- 为了在PowerBuilder应用程序中调用存放在动态链接库pbdll.dll中的函数out_num(),需要事先声明。在声明时要明确:(1)函数的作用范围是全局的还是局部的。全局声明可使该函数用于整个应用,局部声明仅使该函数在对象的脚本中有效。(2)必须指明函数返回的数据类型、传递参数的个数和类型,并将存放该函数的动态链接库的名字告诉PowerBuilder。
---- 声明完成后,应用程序可以调用函数out_num() ,调用该函数的代码与调用任何标准的PowerScript函数一样,区别在于:该函数存放在动态链接库中,调用它时,动态链接库装入内存,函数执行。

---- 下面是PowerBuilder中被调用函数的使用声明:

Function int out_num ( int irow ) LIBRARY "pbdll.dll"
在PowerBuilder中调用函数out_num()代码如下:
int irow,retcode
irow=dw_1.rowcount()
retcode=out_num(irow)

四、 加载DLL
---- 当PowerBuilder应用程序调用外部函数时,动态链接库装入内存。操作系统会在如下位置查找动态链接库:(1)EXE文件运行的目录。(2)Windows的系统目录。如果没有找到DLL,应用程序将产生运行错误,显示一个对话框,见图1-2(略)。如果找到DLL,它就被映射到程序的内存空间。
五、 结束语
---- DLL为不同编程环境下的应用程序之间的连接提供了方便,节省了内存,提高了速度,同时也丰富了PowerScript语言的编程能力。


 

---- 本文'一'、'二'两部分适用于对DLL的基本制作方法已经了解,或手头有关于DLL制作方法的书籍的读者.对于初次接触DLL制作的读者,建议您先按'三'中的步骤建立一个自己的DLL并在另一个应用程序中成功的调用它之后再阅读'一'、'二'.

---- DLL可以分为两个不同的类别:用C/C++(不用对象)编写的基于API的传统DLL和基于MFC对象的DLL.

一.两种类型的比较:
---- 1. 基于MFC的DLL限制在使用MFC的编译器中.
---- 基于API的DLL可以从一种编译器移植到另一种编译器.

---- 2. 基于MFC的DLL可以由制作向导构建框架,制作简单

---- 基于API的DLL的制作向导只为你制作了一个空的DLL工程,工程的维护和代码的编写全部需要手工完成(这一点在VC 6.0中有了改进)

---- 3. 基于MFC的DLL不适用与制作读取二进制文件的DLL

---- (无法正确读取与DOS应用程序共享的二进制文件)

---- 基于API的DLL可以正确读取在DOS环境中创建的二进制文件.

---- 造成该结果的原因其实很简单:

---- 在读取二进制文件的过程中通常会使用"结构(体)",基于MFC的DLL要加载MFC,它要求"结构成员位对齐"的比特位是8位,而且你无法方便的通过选中"Project- >Setting- >C/C++"选项卡中的"Code Generation"再修改"Struct member alignment"来使其变为1位(在VC5.0中即使改变了,在编译时该改变也会被忽略.不过这一不足在VC6.0中已经得到了改进,读者有兴趣的话可参见笔者《在VC6.0中读取二进制文件的惊喜》一文).

---- 而基于API的DLL则可以通过以上的方法方便的实现.

二.在实际制作与使用中的一点经验:
---- 1.制作DLL的目的之一是共享资源/代码.所谓"共享"当然不应该仅仅是几个VC++制作的应用程序可以使用,但是在与其他编程语言协作时,有些问题是需要注意的.
---- 在制作DLL时,VC++对函数的省缺声明是"__cedcl",也就是说,如果你在声明你的函数时不作特殊声明的话,你制作的DLL将只能被C/C++调用,如果你想用其他开发语言(比如VB5.0)调用它就会报错,即使调用方法完全正确.

---- 那么该怎么办呢,你一定已经猜到了---不要用省缺的声明方式---一个很好的选择是使用"WINAPI"来声明你的函数.它可以把你的DLL中的函数声明成WINDOWS API供其他程序调用(当然也包括C/C++制作的程序).

---- 2.建议你在制作DLL的同时制作包括导出函数原型声明的.H文件虽然这不是必须的但是若你的DLL是被C/C++调用,.H文件和.LIB文件可以为使用你的DLL的开发人员省去不少精力,当你需要修改/升级你的DLL时更是如此.DLL的C/C++使用者只要在工程中引入.H和.LIB文件可以象使用自己编写的函数一样方便的使用DLL中的函数,不必再使用存储DLL句柄、声明函数型指针、LoadLibrary、GetProcAddress那样繁复的调用方式.

---- 3.虽然你不必编写.DEF文件就能制作出基于API的.DLL文件.但是制作.DEF文件并不难,至少你有捷径可以走.有一个很简单的方法你不妨一试:

---- 例如,你用基于API的方法制作了一个DLL工程文件并为其编写了.CPP和.H文件,你可以保存并关闭该工程,然后在另一个目录中创建一个与其同名的基于MFC的DLL工程.好了,现在你已经知道怎么做了---将该目录中的.DEF文件移动过去就可以了.省下的工作就是再次打开基于API的DLL工程,并将.DEF文件加入工程,将你的导出函数的函数名加到EXPORTS之后,再重新编译工程就OK了.

---- 4.DLL文件的省缺名称是与工程名一致的(也是在.DEF文件中LIBRARY 之后的名字),不要试图在制作完毕之后通过简单的修改.DLL文件的文件名来改变它,这会导致使用该DLL的应用程序错误.

三.一个例子:
---- DLL中定义有两种函数:
---- 导出函数(exportfunction): 可以被其他模块调用
---- 内部函数(internalfunction): 只能在DLL内部使用
---- 创建一个基于API的DLL.本例只定义了导出函数.

---- 1.在FILE- >NEW- >PROJECTS中选择"WIN32 Dynamic-Link Library"在Project Name中输入 "a"按OK

---- 2.在FILE- >NEW- >FILES中选择C++ SOURCE FILE,在FILE中输入a.cpp,按OK

---- 在FILE- >NEW- >FILES中选择TEXT文件,在FILE中输入a.h,按OK

来源:(http://blog.sina.com.cn/s/blog_50a0aa5e0100fzwq.html) - VC++怎样生成DLL_孟宪波_新浪博客

---- 在FILE- >NEW- >FILES中选择TEXT文件,在FILE中输入a.def,按OK

---- 3.源文件:

    //---------------------------
    //a.cpp
    #include < windows >
    WINAPI int add(int a,int b)
    {    return (a+b);
    }
    //---------------------------
    //a.h
    WINAPI int add(int a,int b);
    //---------------------------
    //a.def
    LIBRARY    "aaa"    ;指出DLL的名字
    DESCRIPTION 'aaa Windows Dynamic Link Library'
    ;描述DLL的用途(此句可选)
    EXPORTS        add    ;导出函数的名字

四.调用DLL的方法:
---- 1.通常我们在调用DLL时所需的DLL文件必须位于以下三个目录之一:
---- (1)Windows的系统目录:/windows/system;

---- (2)DOS中path所指出的任何目录;

---- (3)程序所在的目录;

---- 同时应注意管理好你的.lib文件和.h和文件

---- 2.建立一个工程,简单起见可建立一个控制台应用程序.

---- 3.在工程中引入a.lib:

---- (1)如果你的a.lib放在VC标准的LIB文件夹中.

    单击Project- >Project Settings...
    在link选卡的object/library modules中加上a.lib即可

---- (2)如果你的a.lib不是放在VC标准的LIB文件夹中
    单击Project- >Add to Project- >files...
    找到a.lib文件,按OK
< pre >
4.//------------------------
    //call_a.cpp
    #include< stdio.h >
    #include "c:/a/a.h"
    void main(void)
    {    int c=0;

        c=add(1,2);
        printf("1+2=%d",c);
    }
    //本程序在VC5.0下调试通过

创建“通用的”动态链接库(DLL)
VCKBASE
    最近有许多人问如何让动态链接库的输出函数能够被任何支持动态链接库的语言调用。写动态链接库是很EASY的事情。但是,他们大多觉得输出的名字有乱字符(如:
_vbShiftRight@1)。我想在这里就讨论一下如何让输出函数的名字中不出现乱子符。

    首先,除非你绝对需要使用C++编码,否则我还是推荐使用C来写DLL。这里我想让创建的DLL可以在VB中使用。

    你需要实现自己DLL的入口点函数和保证代码使用stdcall调用规范,但这要依赖你使用的编译器。例如,你可以在VC中使用“/entry:"DLLEntry"”命令行编译选项来创建自己的入口点。“DLLEntry” 可以参考下列代码:
/////////////////////////////////////////////////////////////////////
// DLL initialization and clean-up.
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch(fdwReason) {

    case DLL_PROCESS_ATTACH:

        // Perform any DLL initialization here
        break;

    case DLL_PROCESS_DETACH:

        // Perform any DLL cleanup here
        break;

    }
    return TRUE;
}

为了保证你使用正确的调用规范,要通知编译器使用stdcall规范和/或使用在windows.h(及相关文件)中定义的常量,如WINAPI等。通常DLL的代码如下:
/////////////////////////////////////////////////////////////////////
// Shifts bits right for integers.
WORD WINAPI vbShiftRight(WORD nValue, WORD nBits)
{
    return (nValue >> nBits);
}

下一步是与你在微软文档中读到的内容相反。你需要创建一个DEF文件。这是你防止输出函数名不出现乱字符的唯一方式(如_vbShiftRight@1)。DEF文件的形式如下:

EXPORTS
vbShiftRight

下一步是在VB中调用这个函数,使用以下声明:
Declare Function vbShiftRight Lib "MYDLL.DLL" (ByVal nValue As Integer,
ByVal nBits As Integer)

As Integer

Sub Test()
    Dim i As Integer
    i = vbShiftRight(4, 2)
    Debug.Assert i = 1
End Sub

如果你还想要更容易的方法从VB中调用,可以创建一个类型库。为此你需要创建和编译ODL(对象描述语言)文件。这个文件应该包含如下内容:
module MyModule {
    [
    helpstring("Shifts the bits of an integer to the right."),
    entry("vbShiftRight")
    ]
    short _stdcall vbShiftRight([in] short nValue, [in] short nBits);
};

    当VB加载DLL的类型库时,函数名和参数将出现在VB的对象浏览器中。此外,如果用户不输入正确的参数类型,VB将产生一个错误。

来源:(http://blog.sina.com.cn/s/blog_50a0aa5e0100fzwq.html) - VC++怎样生成DLL_孟宪波_新浪博客
原创粉丝点击