使用Borland C++ Builder來編寫DLLs

來源:互聯網
上載者:User
使用Borland C++ Builder來編寫DLLs
撰稿人: [尹加俊(yinjiajun@gmail.com) 南京順成科技]   
2005-05-16
前言
網路上流傳的BCB編寫和調用DLL的方法多來源於一篇《BCB 編寫 DLL 終極手冊》,多數網站在轉載此文章時也並未註明出處和作者,甚為心寒,且在轉載過程中難免有紕漏,致使一些例子無法正確運行,我根據網路資料,重新整理了一下,發布出來。
如欲轉載,請註明出處和作者,並向作者發一封郵件,謝謝。

一.注意:
建立動態連結程式庫時,如果想你建立的動態連結程式庫並非只用於Borland開發工具,那麼就需要遵循發下規則:
(1).在匯出函數的傳回值和參數中不要使用Borland特有的資料類型和結構體,如AnsiString之類,請使用C/C++標準的資料類型或使用C/C++標準資料類型定義的結構體(特別不要使用String資料類型,BCB DLL嚮導產生的DLL工程檔案中大篇幅的說明就是對此的說明,請自己查閱);
(2).請使用extern "C"命名規範,這樣,產生的DLL中的匯出函數,就不會使用C++的命名規範,而是使用的C命名規範,即匯出函數不會名字分解,而是和你定義的函數相同;
(3).匯出函數請使用WIN32 API的調用方式__stdcall(即WINAPI)或VC與BorlandC++的呼叫慣例__cdecl,不要使用Borland特有的__fastcall呼叫慣例,否則只有Borland開發工具才可以使用這些動態連結程式庫;

二.執行個體:
(1).匯出函數(不使用VCL)
使用BCB建立DLL嚮導來建立一個工程,選擇不使用VCL,代碼如下:
//---------------------------------------------------------------------------
#include
//---------------------------------------------------------------------------
//   Important note about DLL memory management when your DLL uses the
//   static version of the RunTime Library:
//
//   If your DLL exports any functions that pass String objects (or structs/
//   classes containing nested Strings) as parameter or function results,
//   you will need to add the library MEMMGR.LIB to both the DLL project and
//   any other projects that use the DLL.  You will also need to use MEMMGR.LIB
//   if any other projects which use the DLL will be performing new or delete
//   operations on any non-TObject-derived classes which are exported from the
//   DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling
//   EXE's to use the BORLNDMM.DLL as their memory manager.  In these cases,
//   the file BORLNDMM.DLL should be deployed along with your DLL.
//
//   To avoid using BORLNDMM.DLL, pass string information using "char *" or
//   ShortString parameters.
//
//   If your DLL uses the dynamic version of the RTL, you do not need to
//   explicitly add MEMMGR.LIB as this will be done implicitly for you
//---------------------------------------------------------------------------
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    return 1;
}
//---------------------------------------------------------------------------
extern "C" __declspec(dllexport) int __stdcall Calc(int a, int b) //匯出函數
{
    return a+b;
}
//---------------------------------------------------------------------------
儲存工程為DLLs,編譯,就會在工程目錄下產生DLLs.dll(大小應該是8K),同時還會自動在同一目錄下產生DLLs.lib靜態庫,如果沒有產生,請自己手動使用implib.exe工具產生(使用方法見本文說明)。

(2).匯出函數(使用VCL)
使用BCB DLL嚮導建立一個工程,選擇使用VCL支援,建立立一個表單(採用預設名稱TForm1)存為Unit1.cpp,設定表單大小為一般OKCANCEL對框的大小(這裡設為277*119),在表單上添加兩個按鈕:Button1標籤為"確定",ModalResult為mrOk,Button2標籤為"取消",ModalResult為mrCancel;
然後在DLL主程式中引用剛才建立的表單,並添加匯出函數,代碼如下:
//---------------------------------------------------------------------------
#include
#include
#pragma hdrstop
//---------------------------------------------------------------------------
//   Important note about DLL memory management when your DLL uses the
//   static version of the RunTime Library:
//
//   If your DLL exports any functions that pass String objects (or structs/
//   classes containing nested Strings) as parameter or function results,
//   you will need to add the library MEMMGR.LIB to both the DLL project and
//   any other projects that use the DLL.  You will also need to use MEMMGR.LIB
//   if any other projects which use the DLL will be performing new or delete
//   operations on any non-TObject-derived classes which are exported from the
//   DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling
//   EXE's to use the BORLNDMM.DLL as their memory manager.  In these cases,
//   the file BORLNDMM.DLL should be deployed along with your DLL.
//
//   To avoid using BORLNDMM.DLL, pass string information using "char *" or
//   ShortString parameters.
//
//   If your DLL uses the dynamic version of the RTL, you do not need to
//   explicitly add MEMMGR.LIB as this will be done implicitly for you
//---------------------------------------------------------------------------
#include "Unit.h" //引用設計的表單
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    return 1;
}
//---------------------------------------------------------------------------
extern "C" __declspec(dllexport) int __stdcall UserClick(void) //匯出函數
{
    TForm1 *Form1 = new TForm1(NULL);
    if(Form1->ShowModal() == mrOk) {
        delete Form1;
        return 1;
    } else {
        delete Form1;
        return 0;
    }
}
//---------------------------------------------------------------------------
儲存工程為DLLs,編譯,就會在工程目錄下產生DLLs.dll,同時還會自動在同一目錄下產生DLLs.lib靜態庫,如果沒有產生,請自己手動使用implib.exe工具產生。

(3).匯出類
使用BCB建立DLL嚮導來建立一個工程,選擇不使用VCL(本例不使用VCL,是否支援VCL是視你自己的應用而定),代碼如下:
//---------------------------------------------------------------------------
#include
//---------------------------------------------------------------------------
//   Important note about DLL memory management when your DLL uses the
//   static version of the RunTime Library:
//
//   If your DLL exports any functions that pass String objects (or structs/
//   classes containing nested Strings) as parameter or function results,
//   you will need to add the library MEMMGR.LIB to both the DLL project and
//   any other projects that use the DLL.  You will also need to use MEMMGR.LIB
//   if any other projects which use the DLL will be performing new or delete
//   operations on any non-TObject-derived classes which are exported from the
//   DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling
//   EXE's to use the BORLNDMM.DLL as their memory manager.  In these cases,
//   the file BORLNDMM.DLL should be deployed along with your DLL.
//
//   To avoid using BORLNDMM.DLL, pass string information using "char *" or
//   ShortString parameters.
//
//   If your DLL uses the dynamic version of the RTL, you do not need to
//   explicitly add MEMMGR.LIB as this will be done implicitly for you
//---------------------------------------------------------------------------
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    return 1;
}
//---------------------------------------------------------------------------
__declspec(dllexport) __stdcall class TTest{    //聲明匯出類
    int a,b;
public:
    void __stdcall SetValue(int x, int y);
    int __stdcall Calc(void);
};
//---------------------------------------------------------------------------
void __stdcall TTest::SetValue(int x, int y)    //類的實現
{
    this->a = x;
    this->b = y;
}
//---------------------------------------------------------------------------
int __stdcall TTest::Calc(void) //類的實現
{
    return this->a + this->b;
}
//---------------------------------------------------------------------------
儲存工程為DLLs,編譯,就會在工程目錄下產生DLLs.dll,同時還會自動在同一目錄下產生DLLs.lib靜態庫,如果沒有產生,請自己手動使用implib.exe工具產生。
注意,並非所有的代碼都需要在工程DLL主檔案中寫,匯出函數和類等都可以在其它單元中設計,然後在主檔案中#include即可,看自己的習慣,當然了,一個巨大的DLL工程,不可能寫在一個檔案中的。

(4).使用(1)建立的DLL
建立一個工程。
[1].靜態調用:
向工程中添加(1)中產生的靜態庫DLLs.lib,然後在.h中添加匯出函數的定義,如下:
extern "C" __declspec(dllimport) int __stdcall Calc(int,int); //匯出DLL中函數
然後就可以在這個單元中使用int __stdcall Calc(int,int)這個函數了,如:
ShowMessage(IntToStr(Calc(5,10));
[2].動態調用
不需要添加靜態庫.lib檔案,只要在需要調用時才載入DLL,如下:
    HINSTANCE Hdl;
    int __stdcall (*Calc)(int,int); //定義函數原型
    Hdl = ::LoadLibrary("DLLs.dll"); //載入DLL
    if(Hdl != NULL) {
        Calc = (int __stdcall (*)(int,int))::GetProcAddress(Hdl,"Calc"); //擷取函數入口地址
        if(Calc != NULL) {
            ShowMessage(IntToStr(Calc(5,10))); //調用DLL中函數
        } else {
            ShowMessage("不能找到函數入口!");
        }
        ::FreeLibrary(Hdl); //一定不要忘記調用完畢後釋放DLL
    } else {
        ShowMessage("不能載入DLL!");
    }

(5).使用(2)建立的DLL
[1].靜態調用:
向工程中添加(2)中產生的靜態庫DLLs.lib,然後在.h中添加匯出函數的定義,如下:
extern "C" __declspec(dllimport) int __stdcall UserClick(void); //匯出DLL中函數
然後就可以在這個單元中使用int __stdcall UserClick(void)這個函數了,如:
    if(UserClick()) {
        ShowMessage("使用者點擊“確定”");
    } else {
        ShowMessage("使用者點擊“取消”或直接關閉");
    }
[2].動態調用
不需要添加靜態庫.lib檔案,只要在需要調用時才載入DLL,如下:
    HINSTANCE Hdl;
    int __stdcall (*UserClick)(void);
    Hdl = ::LoadLibrary("DLLs.dll");
    if(Hdl != NULL) {
        UserClick = (int __stdcall (*)(void))::GetProcAddress(Hdl,"UserClick");
        if(UserClick != NULL) {
            if(UserClick()) {
                ShowMessage("使用者點擊“確定”");
            } else {
                ShowMessage("使用者點擊“取消”或直接關閉");
            }
        } else {
            ShowMessage("不能找到函數入口!");
        }
        ::FreeLibrary(Hdl);
    } else {
        ShowMessage("不能載入DLL!");
    }

(6).使用(3)建立的DLL
DLL中匯出的類,只能使用表態的方式來調用。本例中的DLL調用方法如下:
向工程中添加(3)中產生的靜態庫DLLs.lib,然後在.h中添加匯出類的聲明,如下:
__declspec(dllimport) __stdcall class TTest{
    int a,b;
public:
    void __stdcall SetValue(int x, int y);
    int __stdcall Calc(void);
};
然後就可以在這個單元中使用TTest這個類了,如:
    TTest *Inst = new TTest;
    Inst->SetValue(5,10);
    ShowMessage(IntToStr(Inst->Calc()));
    delete Inst;

三.一些工具:
(1).impdef.exe
用法:impdef.exe deffile.def yourdll.dll
產生指定DLL檔案的def檔案,可以用它來查看DLL中的函式宣告。例如,BCB使用VC的DLL時,可能需要查看一下VC中匯出函數的函數名;或者未使用extern "C"呼叫慣例時,可以用它來查看DLL中匯出函數的C++命名方式,從而可以正確調用。
(2).implib.exe
用法:implib.exe libfile.lib yourdll.dll
用此工具來產生DLL調用的靜態庫,用於DLL的靜態調用方式。
(3).vctobpru.exe
用此工具可以把VC的工程匯入到BCB工程中,它自動轉換VC的工程檔案為BCB工程檔案,產生相應的.bpr等檔案。
(4).tdump.exe(VC中為dumpbin.exe)
用法:tdump.exe [options] [inputfile] [listfile] [options]
用此工具可以查看DLL中的匯出函式宣告等等,具體用法請運行tdump.exe(不加參數)。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.