程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C++在VS下創建、調用dll

C++在VS下創建、調用dll

編輯:關於C語言

代碼復用是提高軟件開發效率的重要途徑。一般而言,只要某部分代碼具有通用性,就可將它構造成相對獨立的功能模塊並在之後的項目中重復使用。比較常見的例子是各種應用程序框架,ATL、MFC等,它們都以源代碼的形式發布。由於這種復用是“源碼級別”的,源代碼完全暴露給了程序員,因而稱之為“白盒復用”。“白盒復用”的缺點比較多,總結起來有4點。
暴露了源代碼;多份拷貝,造成存儲浪費;
容易與程序員的“普通”代碼發生命名沖突;
更新功能模塊比較困難,不利於問題的模塊化實現;
實際上,以上4點概括起來就是“暴露的源代碼”造成“代碼嚴重耦合”。為了彌補這些不足,就提出了“二進制級別”的代碼復用。使用二進制級別的代碼復用一定程度上隱藏了源代碼,對於緩解代碼耦合現象起到了一定的作用。這樣的復用被稱為“黑盒復用”。
:實現“黑盒復用”的途徑不只dll一種,靜態鏈接庫甚至更高級的COM組件都是。

參考程序原文:http://msdn.microsoft.com/zh-cn/library/ms235636.aspx
新建“Win32項目”,選擇應用程序類型為"DLL”,其他默認。添加頭文件testdll.h

 TESTDLL_API __declspec(dllexport)   
  
 TESTDLL_API __declspec(dllimport)   
  

    
         TESTDLL_API  Add( a, 
         TESTDLL_API  Subtract( a, 
         TESTDLL_API  Multiply( a, 
         TESTDLL_API  Divide( a, 

當定義了符號TESTDLL_EXPORTS,TESTDLL_API被設置為 __declspec(dllexport) 修飾符,。若未定義則TESTDLL_API被設置為__declspec(dllimport),。當DLL項目生成時,TESTDLL_EXPORTS默認是定義的,所以默認設置的是__declspec(dllexport) 修飾符。
添加cpp文件

#include <stdexcept>  
  MyMathFuncs::Add( a,  a + MyMathFuncs::Subtract( a,  a - MyMathFuncs::Multiply( a,  a * MyMathFuncs::Divide( a,  (b ==  invalid_argument( a /

編譯就會生成對應的dll文件,同時也會生成對應的lib文件。
:a.DLL中導出函數的聲明有兩種方式:在函數聲明中加上__declspec(dllexport);采用模塊定義(.def)文件聲明。詳見:http://www.cnblogs.com/enterBeijingThreetimes/archive/2010/08/04/1792099.html
b.對於C文件創建dll時或者想使用C編譯器創建dll時,建議使用 extern “C” 標志,參見extern "C"的簡單解析

應用程序使用DLL可以采用兩種方式:一種是隱式鏈接(調用),另一種是顯式鏈接。在使用DLL之前首先要知道DLL中函數的結構信息。VS在VC\bin目錄下提供了一個名為Dumpbin.exe的小程序,用它可以查看DLL文件中的函數結構。兩種的對比詳見:http://blog.sina.com.cn/s/blog_53004b4901009h3b.html
采用靜態加載的方式,比較簡單,需要.h、.lib、.dll三件套。新建“控制台應用程序”或“空項目”。配置如下:
項目->屬性->配置屬性->VC++ 目錄-> 在“包含目錄”裡添加頭文件testdll.h所在的目錄
項目->屬性->配置屬性->VC++ 目錄-> 在“庫目錄”裡添加頭文件testdll.lib所在的目錄
項目->屬性->配置屬性->鏈接器->輸入-> 在“附加依賴項”裡添加“testdll.lib”(若有多個 lib 則以空格隔開)
添加cpp文件

#include <iostream>  
  a =  b = <<  <<<<<<  <<<<<<  <<<<<<  <<<<<<  <<) << ( invalid_argument &<<  << e.what() << 

現在可以編譯通過了,但是程序運行就報錯,還需要將testdll.dll復制到當前項目生成的可執行文件所在的目錄。
是應用程序在執行過程中隨時可以加載DLL文件,也可以隨時卸載DLL文件,這是隱式鏈接所無法作到的,所以顯式鏈接具有更好的靈活性,對於解釋性語言更為合適。
新建項目,不需要特殊配置,添加cpp文件

<Windows.h> 
#include<iostream>
  (*pAdd)( a,  (*pSubtract)( a, = LoadLibrary(); 
    (hDLL !== pAdd(GetProcAddress(hDLL, MAKEINTRESOURCE())); 
        (fp1 !=<<fp1(, )<<<<<<<<= pSubtract(GetProcAddress(hDLL, )); 
        (fp2 !=<<fp2(, )<<<<<<<<<<<<<< 

在DLL文件中,dll工程中函數名稱發生了變化(C++編譯器),在DLL文件中稱變化後的字符為“name標示”。GetProcAddress中第二個參數可以由DLL文件中函數的順序獲得,或者直接使用DLL文件中的”name標示”,這個標示可以通過Dumpbin.exe小程序查看。如果C++編譯器下,想讓函數名更規范(和原來工程中一樣),具體方法詳見:http://blog.csdn.net/btwsmile/article/details/6676802。
當然,為了讓函數名更規范,最常用的方式是:創建dll過程中使用C編譯器來編譯函數,這樣DLL文件中的函數名和原dll工程中的函數名就一致了。

為了解決上部分最後的問題,可以使用 extern “C” 為dll工程中的函數建立C連接,簡單的示例工程如下。
在DLL創建的工程中,添加cpp文件

#include 
  {                  
 addfun( a,  a+

編譯即可生成DLL文件。在dll調用工程中,添加cpp文件

<windows.h><iostream>
 (*FUNA)(,= LoadLibrary();
    = (FUNA)GetProcAddress(hMod, TEXT( 
         (addfun !=<<addfun(, )<<<<<<<<<<

運行,這樣便可以調用dll的函數了。再進一步,上述dll文件如果通過隱式調用,利用.dll、.lib文件,調用函數應為

#include <iostream>
 comment(lib,"cdll.lib")
   _declspec(dllimport)  addfun( a,
<<addfun(,)<<

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved