新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 中文XML论坛 - 专业的XML技术讨论区计算机技术与应用『 C/C++编程思想 』 → BCB编写DLL终极手册 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 8695 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: BCB编写DLL终极手册 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客楼主
    发贴心情 BCB编写DLL终极手册

    一. 编写 DLL
      File/New/Dll 生成 Dll 的向导,然后可以添加导出函数和导出类
      导出函数:extern "C" __declspec(dllexport) ExportType FunctionName(Parameter)
      导出类:class __declspec(dllexport) ExportType ClassName{...}
      例子:(说明:只是生成了一个 DLL.dll )

    #include "DllForm.h"  // TDllFrm 定义

    USERES("Dll.res");
    USEFORM("DllForm.cpp", DllFrm);

    class __declspec(dllexport) __stdcall MyDllClass { //导出类
        public:
           MyDllClass();
           void CreateAForm();
           TDllFrm* DllMyForm;
    };

    TDllFrm* DllMyForm2;
    extern "C" __declspec(dllexport) __stdcall void CreateFromFunct();//导出函数

    //---------------------------------------------------------------------------
    int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
    {
        return 1;
    }
    //---------------------------------------------------------------------------

    MyDllClass::MyDllClass()
    {
    }

    void MyDllClass::CreateAForm()
    {
        DllMyForm = new TDllFrm(Application);
        DllMyForm->Show();
    }
    //---------------------------------------------------------------------------
    void __stdcall CreateFromFunct()
    {
        DllMyForm2 = new TDllFrm(Application);
        DllMyForm2->Show();
    }


    二. 静态调用 DLL
    使用 $BCB path\Bin\implib.exe 生成 Lib 文件,加入到工程文件中
    将该文件拷贝到当前目录,使用 implib MyDll.lib MyDll.dll 生成
    // Unit1.h // TForm1 定义
    #include "DllForm.h" // TDllFrm 定义
    //---------------------------------------------------------------------------

    __declspec(dllimport) class __stdcall MyDllClass {
        public:
            MyDllClass();
            void CreateAForm();
            TDllFrm* DllMyForm;
    };
    extern "C" __declspec(dllimport) __stdcall void CreateFromFunct();

    class TForm1 : public TForm{...}


    // Unit1.cpp // TForm1 实现
    void __fastcall TForm1::Button1Click(TObject *Sender)
    { // 导出类实现,导出类只能使用静态方式调用
        DllClass = new MyDllClass();
        DllClass->CreateAForm();    
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    { // 导出函数实现
        CreateFromFunct();
    }
    //---------------------------------------------------------------------------

    void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
    {
        delete DllClass;
    }

    三. 动态调用 DLL
    // Unit1.h
    class TForm1 : public TForm
    {
    ...
    private: // User declarations
    void (__stdcall *CreateFromFunct)();
    ...
    }

    // Unit1.cpp // TForm1
    HINSTANCE DLLInst = NULL;
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
        if( NULL == DLLInst ) DLLInst = LoadLibrary("DLL.dll"); //上面的 Dll
        if (DLLInst) {
            CreateFromFunct = (void (__stdcall*)()) GetProcAddress(DLLInst,
                                                        "CreateFromFunct");
            if (CreateFromFunct) CreateFromFunct();
            else ShowMessage("Could not obtain function pointer");
        }
        else ShowMessage("Could not load DLL.dll");
    }

    void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
    {
        if ( DLLInst ) FreeLibrary (DLLInst);
    }
      
    四. DLL 作为 MDIChild (子窗体) 【只编写动态调用的例子】
        实际上,调用子窗体的 DLL 时,系统只是检查应用程序的 MainForm 是否为 fsMDIForm 的窗体,这样只

    要把调用程序的 Application 的 Handle 传递给 DLL 的 Application 即可;同时退出 DLL 时也要恢复

    Application

    // MDIChildPro.cpp // Dll 实现 CPP
    #include "unit1.h" // TForm1 定义
    TApplication *SaveApp = NULL;
    int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
    {
        if ( (reason==DLL_PROCESS_DETACH) && SaveApp )
            Application = SaveApp ; // 恢复 Application
        return 1;
    }

    extern "C" __declspec(dllexport) __stdcall void TestMDIChild(    //1024X768
        TApplication* mainApp,
        LPSTR lpCaption)
    {
        if ( NULL == SaveApp ) // 保存 Application,传递 Application
        {
            SaveApp = Application;
            Application = mainApp;
        }
        // lpCaption 为子窗体的 Caption
        TForm1 *Form1 = new TForm1 ( Application, lpCaption );
        Form1->Show();
    }
    注:上面的程序使用 BCB 3.0 编译成功

    五. BCB 调用 VC 编写的 DLL
      1. 名字分解:
        没有名字分解的函数
            TestFunction1 // __cdecl calling convention
            @TestFunction2 // __fastcall calling convention
            TESTFUNCTION3 // __pascal calling convention
            TestFunction4 // __stdcall calling convention
        有名字分解的函数
            @TestFunction1$QV // __cdecl calling convention
            @TestFunction2$qv // __fastcall calling convention


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2008/10/24 8:49:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客2
    发贴心情 
    TESTFUNCTION3$qqrv // __apscal calling convention
            @TestFunction4$qqrv // __stdcall calling convention
        使用 extern "C" 不会分解函数名

        使用 Impdef MyLib.def MyLib.DLL 生成 def 文件查看是否使用了名字分解

      2. 调用约定:
        __cdecl 缺省
          是 Borland C++ 的缺省的 C 格式命名约定,它在标识符前加一下划线,以保留
        它原来所有的全程标识符。参数按最右边参数优先的原则传递给栈,然后清栈。
            extaern "C" bool __cdecl TestFunction();
          在 def 文件中显示为
            TestFunction @1
          注释: @1 表示函数的顺序数,将在“使用别名”时使用。

        __pascal Pascal格式
          这时函数名全部变成大写,第一个参数先压栈,然后清栈。
            TESTFUNCTION @1 //def file

        __stdcall 标准调用
          最后一个参数先压栈,然后清栈。
            TestFunction @1 //def file

        __fastcall 把参数传递给寄存器
          第一个参数先压栈,然后清栈。
            @TestFunction @1 //def file

      3. 解决调用约定:
          Microsoft 与 Borland 的 __stdcall 之间的区别是命名方式。 Borland 采用
        __stdcall 的方式去掉了名字起前的下划线。 Microsoft 则是在前加上下划线,在
        后加上 @ ,再后跟为栈保留的字节数。字节数取决于参数在栈所占的空间。每一个
        参数都舍入为 4 的倍数加起来。这种 Miocrosoft 的 DLL 与系统的 DLL 不一样。

      4. 使用别名:
          使用别名的目的是使调用文件 .OBJ 与 DLL 的 .DEF 文件相匹配。如果还没有
        .DEF 文件,就应该先建一个。然后把 DEF 文件加入 Project。使用别名应不断
        修改外部错误,如果没有,还需要将 IMPORTS 部分加入 DEF 文件。
            IMPORTS
            TESTFUNCTIOM4 = DLLprj.TestFunction4
            TESTFUNCTIOM5 = DLLprj.WEP @500
            TESTFUNCTIOM6 = DLLprj.GETHOSTBYADDR @51
          这里需要说明的是,调用应用程序的 .OBJ 名与 DLL 的 .DEF 文件名是等价的,
        而且总是这样。甚至不用考虑调用约定,它会自动匹配。在前面的例子中,函数被
        说明为 __pascal,因此产生了大写函数名。这样链接程序不会出错。

      5. 动态调用例子
    VC DLL 的代码如下:
    extern "C" __declspec(dllexport) LPSTR __stdcall BCBLoadVCWin32Stdcall()
    {
    static char strRetStdcall[256] = "BCB Load VC_Win32 Dll by __stdcall mode is OK!";

    return strRetStdcall;
    }

    extern "C" __declspec(dllexport) LPSTR __cdecl BCBLoadVCWin32Cdecl()
    {
    static char strRetCdecl[256] = "BCB Load VC_Win32 Dll by __cdecl mode is OK!";

    return strRetCdecl;
    }

    extern "C" __declspec(dllexport) LPSTR __fastcall BCBLoadVCWin32Fastcall()
    {
    static char strRetFastcall[256] = "BCB Load VC_Win32 Dll by __fastcall mode is OK!";

    return strRetFastcall;
    }

         其实动态调用与调用 BCB 编写的 DLL 没有区别,关键是查看 DLL 的导出函数名字
         可以使用 tdump.exe(BCB工具) 或者 dumpbin.exe(VC工具) 查看
         tdump -ee MyDll.dll >1.txt (查看 1.txt 文件即可)
         由于 VC6 不支持 __pascall 方式,下面给出一个三种方式的例子
    void __fastcall TForm1::btnBLVCWin32DynClick(TObject *Sender)
    {
        /*cmd: tdbump VCWin32.dll >1.txt
    Turbo Dump  Version 5.0.16.4 Copyright (c) 1988, 1998 Borland International
                        Display of File VCWIN32.DLL

    EXPORT ord:0000='BCBLoadVCWin32Fastcall::'
    EXPORT ord:0001='BCBLoadVCWin32Cdecl'
    EXPORT ord:0002='_BCBLoadVCWin32Stdcall@0'
        */
        if ( !DllInst )
            DllInst = LoadLibrary ( "VCWin32.dll" );
        if ( DllInst )
        {
            BCBLoadVCWin32Stdcall = (LPSTR (__stdcall *) () )
                GetProcAddress ( DllInst, "_BCBLoadVCWin32Stdcall@0" ); //VC Dll
                // GetProcAddress ( DllInst, "BCBLoadVCWin32Stdcall" ); //BCB Dll
            if ( BCBLoadVCWin32Stdcall )
            {
                ShowMessage( BCBLoadVCWin32Stdcall() );
            }
            else ShowMessage ( "Can't find the __stdcall Function!" );

            BCBLoadVCWin32Cdecl = (LPSTR (__cdecl *) () )
                GetProcAddress ( DllInst, "BCBLoadVCWin32Cdecl" );
            if ( BCBLoadVCWin32Cdecl )
            {
                ShowMessage( BCBLoadVCWin32Cdecl() );
            }
            else ShowMessage ( "Can't find the __cdecl Function!" );

            //Why?不是 'BCBLoadVCWin32Fastcall::',而是 '@BCBLoadVCWin32Fastcall@0'?

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2008/10/24 8:50:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客3
    发贴心情 
    BCBLoadVCWin32Fastcall = (LPSTR (__fastcall *) () )
                //GetProcAddress ( DllInst, "BCBLoadVCWin32Fastcall::" );
                GetProcAddress ( DllInst, "@BCBLoadVCWin32Fastcall@0" );
            if ( BCBLoadVCWin32Fastcall )
            {
                ShowMessage( BCBLoadVCWin32Fastcall() );
            }
            else ShowMessage ( "Can't find the __fastcall Function!" );
        }
        else ShowMessage ( "Can't find the Dll!" );
    }

      6. 静态调用例子
         静态调用有点麻烦,从动态调用中可以知道导出函数的名字,但是直接时(加入 lib 文件到工程文件)

    Linker 提示不能找到函数的实现
         从 4 看出,可以加入 def 文件连接
         (可以通过 impdef MyDll.def MyDll.dll 获得导出表)
         建立与 DLL 文件名一样的 def 文件与 lib 文件一起加入到工程文件
         上面的 DLL(VCWIN32.dll) 的 def 文件为(VCWIN32.def):
    LIBRARY     VCWIN32.DLL

    IMPORTS
        @BCBLoadVCWin32Fastcall     = VCWIN32.@BCBLoadVCWin32Fastcall@0
        _BCBLoadVCWin32Cdecl        = VCWIN32.BCBLoadVCWin32Cdecl
        BCBLoadVCWin32Stdcall       = VCWIN32._BCBLoadVCWin32Stdcall@0

    对应的函数声明和实现如下:
    extern "C" __declspec(dllimport) LPSTR __fastcall BCBLoadVCWin32Fastcall();
    extern "C" __declspec(dllimport) LPSTR __cdecl BCBLoadVCWin32Cdecl();
    extern "C" __declspec(dllimport) LPSTR __stdcall BCBLoadVCWin32Stdcall();

    void __fastcall TfrmStatic::btnLoadDllClick(TObject *Sender)
    {
        ShowMessage ( BCBLoadVCWin32Fastcall() );
        ShowMessage ( BCBLoadVCWin32Cdecl() );
        ShowMessage ( BCBLoadVCWin32Stdcall() );
    }
    注意:在 BCB 5.0 中,可能直接按下 F9 是不能通过 Linker 的,请先 Build 一次
    注:上面的程序使用 BCB 5.0 与 VC6.0 编译成功

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2008/10/24 8:51:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2025/2/8 20:18:50

    本主题贴数3,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    4,312.500ms