• 注册
  • 关于作者
    企业认证:趣记站长
    关注 6 粉丝 4 喜欢 9 内容 992
    江西省·赣州市
    聊天 送礼
    • 查看作者
    • 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

              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 把参数传递给寄存器

            第一个参数先压栈,

      在BCB下使用GExperts的Debug功能
      用C++ Builder实现VFP数据库开发,用BCB开发有身份认证功能的Email程序,BCB动态生成30个按钮对象,BCB不让应用程序显示在任务栏上的方法,利用C++Builder自定义Windows窗体“系统菜单”,用程序实现文件的关联,数字小键盘指法练习,用C++ Builder开发多层数据库应用程序,在C++ Builder6上使用Boost正则表达式库,C++Builder使用经验谈,用C++ Builder对图像进行特殊效果处理,CBuilder中帮助文件的连接及显示讨论,BCB客户端tuxedo开发实例,在BCB下使用GExperts的Debug功能,BCB编写DLL终极手册,在拷贝、删除文件时显示飞行的文件夹动画,用BCB实现超星格式转换为BMP格式,在C++Builder中使用Compress Html Help,在bcb里实现像Winamp那样具有吸附效果的磁性窗口,利用BCB巧建WEB浏览器
      C++ Builder

      然后清栈。

              @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'?

              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 编译成功

      在BCB下使用GExperts的Debug功能
      用C++ Builder实现VFP数据库开发,用BCB开发有身份认证功能的Email程序,BCB动态生成30个按钮对象,BCB不让应用程序显示在任务栏上的方法,利用C++Builder自定义Windows窗体“系统菜单”,用程序实现文件的关联,数字小键盘指法练习,用C++ Builder开发多层数据库应用程序,在C++ Builder6上使用Boost正则表达式库,C++Builder使用经验谈,用C++ Builder对图像进行特殊效果处理,CBuilder中帮助文件的连接及显示讨论,BCB客户端tuxedo开发实例,在BCB下使用GExperts的Debug功能,BCB编写DLL终极手册,在拷贝、删除文件时显示飞行的文件夹动画,用BCB实现超星格式转换为BMP格式,在C++Builder中使用Compress Html Help,在bcb里实现像Winamp那样具有吸附效果的磁性窗口,利用BCB巧建WEB浏览器
      C++ Builder

    • 0
    • 0
    • 0
    • 64
    • 单栏布局 侧栏位置: