一步一步教你用VC和VB調用C++ DLL

來源:互聯網
上載者:User

Step by Step: Calling C++ DLLs from VC++ and VB
一步一步教你用VC和VB調用C++ DLL.
作者 Hans Dietrich    翻譯煙灰
介紹
本系列教程討論了普通情況下4種使用DLL的方法

Part 1

 從VC++應用程式調用C++ DLL的函數

 
從VC++應用程式調用C++ DLL的類

 
Part 2

 從VB應用程式調用C++ DLL的函數

 
Part 3

 從VB應用程式調用C++ DLL的類

 
Part 4

 從VC++應用程式動態調用C++ DLL的函數

 

 

從VC++應用程式調用C++ DLL的函數
Visual Studio 6 使建立包含函數或類的動態串連庫(DLL) 變得非常容易.

 

 

第一步
開啟 Visual Studio 然後選擇 File | New功能表項目:

選擇 Win32 Dynamic Link Library, 輸入工程名, 敲 OK.

選擇 A DLL that exports some symbols  並單擊Finish.在File View裡你會看到如下的工程檔案:

 

第二步
在Test.cpp裡,你將看到如下代碼:

// Test.cpp : Defines the entry point for the DLL application.//#include "stdafx.h"#include "Test.h"BOOL APIENTRY DllMain( HANDLE hModule,                        DWORD  ul_reason_for_call,                        LPVOID lpReserved){    switch (ul_reason_for_call)    {        case DLL_PROCESS_ATTACH:        case DLL_THREAD_ATTACH:        case DLL_THREAD_DETACH:        case DLL_PROCESS_DETACH:            break;    }    return TRUE;}// This is an example of an exported variableTEST_API int nTest=0;// This is an example of an exported function.TEST_API int fnTest(void){    return 42;}// This is the constructor of a class that has been exported.// see Test.h for the class definitionCTest::CTest(){     return; }
Test.cpp 包含了 fnTest 和 CTest::CTest.如果你現在編譯Test.dll, 你將會得到一個可以被其他VC++應用程式直接調用的DLL.   允許其他VC++程式調用的關鍵機制?( key mechanism)就包含在 Test.h中:
// The following ifdef block is the standard way of creating macros// which make exporting from a DLL simpler. All files within this DLL// are compiled with the TEST_EXPORTS symbol defined on the command line.// This symbol should not be defined on any project that uses this DLL.// This way any other project whose source files include this file see // TEST_API functions as being imported from a DLL, whereas this DLL// sees symbols defined with this macro as being exported.#ifdef TEST_EXPORTS#define TEST_API __declspec(dllexport)#else#define TEST_API __declspec(dllimport)#endif// This class is exported from the Test.dllclass TEST_API CTest {public:    CTest(void);    // TODO: add your methods here.};extern TEST_API int nTest;TEST_API int fnTest(void);
這裡面發生了什麼? #ifdef TEST_EXPORTS是什麼意思? TEST_EXPORTS又是在哪定義的?
TEST_EXPORTS如果被定義, 那麼TEST_API將會被定義為 __declspec(dllexport) (DLL匯出), 否則,將會被定義為__declspec(dllimport)(DLL匯入).  這將影響到後邊定義的Ctest類是匯出類還是匯入類. 這意味著如果我們需要匯出的時候,我們就得定義TEST_EXPORTS. 當一個VC++應用程式要訪問這個DLL的時候,可以將Test.lib連結進去,它包含了DLL的匯出符號.

第三步
TEST_EXPORTS 在哪裡被定義了呢? DLL wizard幹了一件我討厭的事,它把TEST_EXPORTS放到了命令列裡.  選擇 Project | Settings | C/C++ | General, 你將看到工程選項:

當然了,這個辦法是可行的. 但是它卻容易讓人忽計,並且可能導致維護上的麻煩. 我比較喜歡清楚明白的定義TEST_EXPORTS : 從項目選項裡邊去掉/D "TEST_EXPORTS",然後在Test.cpp 裡來定義它:
// Test.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#define TEST_EXPORTS                     // <===  ADD THIS LINE
#include "Test.h"

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved)
{
.
.
.
注意 #define TEST_EXPORTS 在 #include "Test.h"前邊. 所以,它定義要在標頭檔裡.現在,可以像先前那樣重新編譯我們的Test.dll,  我們將得到一個可以被其他VC應用程式所調用的DLL.

 
第四步
我們如何調用DLL裡的函數呢? 舉個例子吧, 我用VS建立一個樣本.  選MFC AppWizard (exe),輸入項目名字,然後點OK. 選擇基於對話方塊. 然後點Finish.  開啟 XXXDlg.cpp(XXX是你的工程名字.) 找到OnInitDialog()成員函數, 敲進去如下的代碼:

    .    .    .    // Set the icon for this dialog.  The framework does this automatically    //  when the application's main window is not a dialog    SetIcon(m_hIcon, TRUE);            // Set big icon    SetIcon(m_hIcon, FALSE);        // Set small icon        // code to test Test.dll function:    int n = fnTest();                    // <=== ADD THIS LINE    // code to test the CTest class:    CTest test;                          // <=== ADD THIS LINE        return TRUE;  // return TRUE  unless you set the focus to a control}
第五步
我們還沒寫完代碼呢, 現在要把 Test.h這個DLL的標頭檔包含進去:
// TestExeDlg.cpp : implementation file//#include "stdafx.h"#include "TestExe.h"#include "TestExeDlg.h"#include "Test.h"                        // <=== ADD THIS LINE...
第六步
如果你想趕時間做一個示範的話, 你可能會嘗試只是拷貝DLL的 test.h 到你的項目目錄裡去,那麼編譯器會找到它.   但是當項目很大的時候,這可不是個好主意, 因為當你更新你的DLL檔案時,可能會遇上危險.比如忘了拷貝它到你的exe的目錄中去.   這裡有個簡單的方法來解決這個問題 : 選擇Project | Settings | C/C++ | Settings | Preprocessor, 並且添加Additional include directories: (DLL工程的目錄)

提示  這樣做實際上是假設DLL項目和EXE項目擁有同一個項目目錄.

現在當我編譯的時候, 我得到了一個 linker errors!!
Deleting intermediate files and output files for project 'TestExe - Win32 Debug'.
--------------------Configuration: TestExe - Win32 Debug--------------------
Compiling resources...
Compiling...
StdAfx.cpp
Compiling...
TestExe.cpp
TestExeDlg.cpp
Generating Code...
Linking...
TestExeDlg.obj : error LNK2001: unresolved external symbol "__declspec(dllimport)
public: __thiscall CTest::CTest(void)" (__imp_??0CTest@@QAE@XZ)
TestExeDlg.obj : error LNK2001: unresolved external symbol "__declspec(dllimport)
int __cdecl fnTest(void)" (__imp_?fnTest@@YAHXZ)
Debug/TestExe.exe : fatal error LNK1120: 2 unresolved externals
Error executing link.exe.

TestExe.exe - 3 error(s), 0 warning(s)

第七步
雖然我已經告訴編譯器DLL符號啦,但是連結器還不知道. 所以我們必須告訴連結器.. 選擇Project | Settings | Link,把DLL的lib檔案加到Object/library modules裡邊去:

----------------------------------------------

第八步
好啦,現在編譯通過. 在我們運行程式前,別忘了一件事: 把Test.dll  拷貝到EXE的目錄裡去.

第九步
接下來,可以放一個 斷點到OnInitDialog()函數裡去, 點 GO(F5)調試運行:

 

可以看到, fnTest 返回了42, 和我們預測的一樣. CTest 類也可以用類似的方法來測試.

要點.
VS的工程嚮導為我們建立VC++DLL提供了很好的開始.
函數,類, 和變數 可以從DLL中匯出.
使用  #define 前置處理器定義, 一個標頭檔將可以被DLL 和應用程式共同使用.
DLL匯出它的符號,並且應用程式匯入這個DLL符號.  當編譯應用程式時,編譯器通過標頭檔看到的DLL符號, 當連結應用程式時, 連結器通過匯入庫(Test.lib)看到DLL符號.
當執行應用程式時,DLL必須放到和EXE相同的目錄中去. DLL也可以放到 windows或者system目錄中,這樣也是可行的, 但是它經常引起某些問題, 所以應該避免這樣使用
注釋:
再實際工作中,我很少用到 第七步中的方法. 這樣做的話,在大的工程中,DLL和Lib檔案將經常變得很難管理.我們會想到要建立一個lib目錄和一個 bin目錄,在這裡邊放進去所有我們要使用的lib檔案 , dll檔案 和exe檔案. 如果這樣做的話,我們怎麼告訴連結器找到lib檔案呢? 有兩種方法來做:

1.  選擇Tools | Options | Directories and set Show directories for 為"Library files". 在下邊添加上我們工程所使用的Lib檔案的路徑.

 

2. 另一種辦法是,選擇 Project | Settings | Link, 選category為 Input ,在下邊的 Additional library path 筐裡輸入工程使用的lib檔案的所在路徑.

哪種方法更好一點呢?這取決於你的開發環境. 第一種方法要求整個工程要共用的設定目錄路徑, 並且所有要求所有的開發人員的VS都必須設定到這些路徑.

第二種方法允許每個工程定製自己的路徑,並且在工程中被儲存,如果開發人員的電腦上存放了同樣的目錄,那麼每個開發人員都可以簽出工程並且設計. ,這樣可以避免在每台機器上都去設定同樣的路徑.

 

到現在,我還沒有說怎樣指定要使用的LIB檔案, 我的辦法是在DLL的Test.h中添加兩行,現在它看起來像下邊的樣子:
 

#ifdef TEST_EXPORTS    #define TEST_API __declspec(dllexport)#else    #define TEST_API __declspec(dllimport)    #pragma message("automatic link to Test.lib")   // <== add this line    #pragma comment(lib, "Test.lib")                // <== add this line#endif// This class is exported from the Test.dllclass TEST_API CTest {public:    CTest(void);};extern TEST_API int nTest;TEST_API int fnTest(void);
這樣做,保證了當工程包含DLL的標頭檔時, 它會自動的把DLL 的lib連結進去,我們可以從VS的OUTPUT視窗看到#pragma message給我們的傳達的"automatic link to Test.lib"這個訊息.

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.