文章出處

動態鏈接庫鏈接外部的客戶端

在工程名"dll"頭文件,添加:

#ifdef dll_API  #else  #define dll_API  _declspec(dllimport)  dll_API int add(int a,int b);  dll_API int jianfa(int a,int b);

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

在工程名"dll"源文件,添加:

#define dll_API _declspec(dllimport)  #include"dll.h"  int add(int a,int b)  {  return a+b;  }  int jianfa(int a,int b)  {  return a-b;  }

編譯后,把dll.dll和dll.lib復制粘貼給工程名為“dlltest”目錄當中。

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

訪問動態鏈接庫的類:

在工程名"dll"頭文件,添加:

#ifdef dll_API  #else  #define dll_API  _declspec(dllimport)  dll_API int add(int a,int b);  dll_API int jianfa(int a,int b);  class dll_API Point  {  public:  void output(int x,int y);  };

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

在工程名"dll"源文件,添加:

#define dll_API _declspec(dllimport)  #include"dll.h"  #include<windows.h>  #include<stdio.h>  int add(int a,int b)  {  return a+b;  }  int jianfa(int a,int b)  {  return a-b;  }  void Point::output(int x,int y)  {//獲取句柄  HWND hwnd=GetForegroundWindow();  HDC hdc=GetDC(hwnd);  char buf[20];  memset(buf,0,20);//將字符數組當中的元素都值為0  sprintf(buf,"x=%d,y=%d",x,y);  TextOut(hdc,0,0,buf,strlen(buf));  ReleaseDc(hwnd,hdc);  }

GetForegroundWindow函數,可以當前使用的句柄

將編譯生成的dll和lib文件復制粘貼到dlltest文件目錄。

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

在"dlltest"添加按鈕,其函數內容為:

void CdlltestDlg::OnOutput()  {  Point pt;  pt.output(5,3);  } 

編譯運行,窗口顯示:

x5,y=3

意味著導出dll的類,還導出了成員函數output。

如果不想導出dll整個類,只是導出指定的成員函數。

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

在“dll”頭文件當中,修改為:

#ifdef dll_API  #else  #define dll_API  _declspec(dllimport)  dll_API int add(int a,int b);  dll_API int jianfa(int a,int b);  class /*dll_API*/ Point  {  public:  dll_API void output(int x,int y);  //dll_API在前面,表示導出這個類的成員函數  //為了證明導出指定函數,我們可以添加一個新的成員函數:  void test();  };

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

在“dll”源文件當中,實現:

#define dll_API _declspec(dllimport)  #include"dll.h"  #include<windows.h>  #include<stdio.h>  int add(int a,int b)  {  return a+b;  }  int jianfa(int a,int b)  {  return a-b;  }  void Point::output(int x,int y)  {//獲取句柄  HWND hwnd=GetForegroundWindow();  HDC hdc=GetDC(hwnd);  char buf[20];  memset(buf,0,20);//將字符數組當中的元素都值為0  sprintf(buf,"x=%d,y=%d",x,y);  TextOut(hdc,0,0,buf,strlen(buf));  ReleaseDc(hwnd,hdc);  }  ////////////////////////////////////////  void Point::test()  {      }  /////////////////////////////////////

用dumpbin查看一下,查出dll沒有導出test,而導出了指定的成員函數output.

然后把”dll“工程的目錄里面的dll和.lib復制粘貼給工程名為“dlltest”目錄當中。

在“dlltest”工程,編譯一下,運行,結果和導出整個類一樣。

PS:雖然dll中沒有導出類,但是在外部還可以聲明其類的對象,利用對象去調用被導出的成員函數。

如果成員函數是私有的,即使被導出了,還因為訪問權限而不能被調用。

額外知識筆記:

1.如果用c++編譯的動態鏈接庫,導出的成員函數名字會發生變化。當用c語言編寫的客戶端去訪問這個動態鏈接庫

就不能識別出被導出的成員函數,因為名字識別不出來。

2.如果用c++編寫的客戶端就可以訪問c++編寫的被導出的函數,因為改變名字是同一種語言的編譯器可以識別出來。

3.如果換成其他的c++編寫的客戶端也不能訪問被導出的函數。

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

為了解決這個問題,解決辦法是不要讓函數名稱發生改變:

在“dll”頭文件當中,修改為:

#ifdef dll_API  #else  #define dll_API  extern "C"/*此處修改,一定要大寫字母*/ _declspec(dllimport)  dll_API int add(int a,int b);  dll_API int jianfa(int a,int b);  class /*dll_API*/ Point  {  public:  dll_API void output(int x,int y);  //dll_API在前面,表示導出這個類的成員函數  //為了證明導出指定函數,我們可以添加一個新的成員函數:  void test();  };

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

在“dll”源文件當中,實現:

#define dll_API extern "C"/*此處修改,一定要大寫字母*/ _declspec(dllimport)  #include"dll.h"  #include<windows.h>  #include<stdio.h>  int add(int a,int b)  {  return a+b;  }  int jianfa(int a,int b)  {  return a-b;  }  void Point::output(int x,int y)  {//獲取句柄  HWND hwnd=GetForegroundWindow();  HDC hdc=GetDC(hwnd);  char buf[20];  memset(buf,0,20);//將字符數組當中的元素都值為0  sprintf(buf,"x=%d,y=%d",x,y);  TextOut(hdc,0,0,buf,strlen(buf));  ReleaseDc(hwnd,hdc);  } 

編譯后,在執行dumpbin可以查看函數名字。

extern "C"的缺陷:

不能夠導出類的成員函數,只能導出全局函數,如:

dll_API int add(int a,int b);

dll_API int jianfa(int a,int b);

而不能導出類的成員函數:

class /*dll_API*/ Point  {  public:  dll_API void output(int x,int y);  void test();  };

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

如果調用約定改變,即使有extern"C",也怒能導出函數。

為了解決這個問題,在“dll”頭文件當中,修改為:

dll_API int _stdcall add(int a,int b);

dll_API int _stdcall jianfa(int a,int b);

使用標準調用約定_stdcall。

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

在“dll”源文件當中,修改:

int _stdcall add(int a,int b)  {  return a+b;  }  int _stdcall jianfa(int a,int b)  {  return a-b;  }  

編譯后,查看函數名字沒有變化,顯示為:

_add@8

_jianfa@8

8表示被導出函數所占的字節數

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

為解決名字改編問題(利用添加def文件),下篇文章再做筆記。

看文倉www.kanwencang.com網友整理上傳,為您提供最全的知識大全,期待您的分享,轉載請注明出處。
歡迎轉載:http://www.kanwencang.com/bangong/20170124/94396.html

文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()