青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Jiang's C++ Space

創(chuàng)作,也是一種學(xué)習(xí)的過程。

   :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::

三年多前我在blog.csdn.net上半轉(zhuǎn)載過一篇文章,關(guān)于DLL入門的,不過內(nèi)容有些凌亂,加上非原創(chuàng),我打算重新寫一下,更突出“快速”,內(nèi)容嘛,就比較精簡了,雖然精簡,看完后寫寫DLL肯定是沒問題的,相信我。

一,快速生成一個DLL

哦,對了,講解還是用VC++ 6.0(簡稱VC6)來講解。在VC6下new一個“Win32 Dynamic-Link Library”的Project,就叫“dllTest”吧,注意不要選擇“MFC AppWizard(dll)”,因為……這不屬于本文的內(nèi)容,其實最重要的是:我不太懂(^_^),然后呢,選擇“An empty DLL project”即可。

接下來就是創(chuàng)建以這兩個文件,并添加到Project中去:

lib.h

#ifndef LIB_H
#define LIB_H
extern "C"  int __declspec(dllexport) add(int x,int y);
#endif

lib.cpp

#include "lib.h"
int add(int x,int y)
{
    
return x + y;
}

Build!(這么簡單的程序不會通不過吧?)你就能看到你的生成目錄下有個文件,叫“dllTest.dll”,這就是我們第一個dll,沒幾行代碼,簡單吧,但麻雀雖小五臟俱全,我們使用Visual Studio提供的工具“Depends”打開這個文件看看,如圖所示,你能看到我們導(dǎo)出的這個函數(shù),add。

這個超微型的dll和普通程序的不同在于add函數(shù)的聲明,多了一個__declspec(dllexport),這個是關(guān)鍵,這個修飾符告訴VC6,這個函數(shù)需要導(dǎo)出,而前面的extern "C"的意思是這個函數(shù)是以C語言的標準來調(diào)用的,如果不加extern "C"的話,會怎么樣呢?自己試試看吧,Build后再用Depends看看生成的dll。

二、使用這個DLL

用VC6的向?qū)?chuàng)建一個“Win32 Console Application”的Project,叫“CallDllTest”,然后選擇“"A Hello, Word!"Application”,為什么用Console?簡單唄。

把CallDllTest.cpp的內(nèi)容換成以下:
CallDllTest.cpp

#include "stdafx.h"
#include 
"windows.h"

typedef 
int ( * lpAddFun)(int,int);

int main(int argc, char* argv[])
{
    HINSTANCE hDll;   
//DLL handle 
    lpAddFun addFun;  //Function pointer
    hDll = LoadLibrary("dllTest.dll");
    
if (hDll != NULL)
    {
  addFun 
= (lpAddFun)GetProcAddress(hDll,"add");   
  
if(addFun!=NULL)
  {
   
int result =  addFun(2,3);    
   printf(
"%d",result);
  }
  FreeLibrary(hDll);
    }   
    
return 0;
}

Build,然后<Ctrl>+<F5>運行,就能看到結(jié)果了,打印了一個“5”出來,說明正常了,有點需要說明的是你得把前面生產(chǎn)的那個DLL和這次生成的EXE放在同一目錄下方可。代碼很簡單,思路就是定義函數(shù)指針類型,加載DLL,獲取要調(diào)用的函數(shù)的指針,然后調(diào)用,這么一個過程。

三、靜態(tài)鏈接

剛才使用LoadLibrary這個API加載DLL的方式叫動態(tài)鏈接,現(xiàn)在來介紹靜態(tài)鏈接,其實靜態(tài)鏈接用得還更多,只不過你不一定注意到而已,不信的話現(xiàn)在查看一下你剛創(chuàng)建的CallDllTest這個Project的Project Settings,如圖:


注意我畫紅線的這個地方,Kernel32.lib,user32.lib和gdi32.lib等,這些lib叫做“導(dǎo)入庫”,并不包含真正有效的代碼,真正有效的代碼是存放在DLL中的,剛才我們所使用的LoadLibrary這個API,其實就是通過Kernel32.lib鏈接到Kernel32.dll中去的,也就是說LoadLibrary的實現(xiàn)存在于Kernel32.dll中,而我們是通過Kernel32.lib來找到它的,如果還有興趣的話,可以用Depends看看Kernel32.dll,看看里面是否有LoadLibrary,里面函數(shù)很多,別看花眼了哦,這可是Windows的核心庫之一,但可能你并沒有找到LoadLibrary,而是找到了,LoadLibraryA和LoadLibraryW,這很正常,因為很多需要使用到字符串的API,都有兩個版本,一個是窄字符版,一個是寬字符版,在程序編譯鏈接的時候,編譯器會根據(jù)你的選項來跟你選擇其中一個,這里暫時不展開了。

那如何靜態(tài)使用前面生成的那個dllTest.dll呢?回到剛才dllTest.dll的那個生成目錄,你會發(fā)現(xiàn)一個叫dllTest.lib的文件,這就是我前面提到“導(dǎo)入庫”,現(xiàn)在改一下CallDllTest.cpp。
CallDllTest.cpp

#include "stdafx.h"

#pragma comment(lib, 
"dllTest.lib")

extern "C"  int __declspec(dllimport) add(int x,int y);

int main(int argc, char* argv[])
{
 
int result =  add(2,3);    
 printf(
"%d",result);
    
return 0;
}

dllTest.lib這個文件得復(fù)制到CallDllTest這個Project的目錄下,否則會報找不到文件,執(zhí)行結(jié)果如何?跟剛才是一樣的,這種方式就叫靜態(tài)鏈接,區(qū)別是什么?不需要在運行時調(diào)用LoadLibrary了,我個人覺得靜態(tài)鏈接用得更多一些。

注意看代碼:

extern "C"  int __declspec(dllimport) add(int x,int y);

這句話很關(guān)鍵,__declspec(dllimport)對應(yīng)了DllTest中的__declspec(dllexport),表示該函數(shù)將從dll中導(dǎo)入,那你也許要問了:“我怎么知道這個dll中有這個函數(shù)?并且還知道這個函數(shù)的參數(shù)類型和返回值類型?該不會也是用Depends去看吧?”呃……這怎么說呢?如果這個dll是你寫的,你當然知道啦,但如果這個Dll不是你寫的話,它的作者往往會提供一個頭文件,就好像你要使用LoadLibrary,你得包含“windows.h”這個頭文件一樣,否則就出現(xiàn)符號未定義的編譯錯誤,那么我們改一下lib.h這個頭文件。

lib.h

#ifndef LIB_H
#define LIB_H
#ifdef DLLTEST_EXPORTS
extern "C" int __declspec(dllexport) add(int x,int y);
#else
extern "C" int __declspec(dllimport) add(int x,int y);
#endif
#endif

在DllTest這個Project中,DLLTEST_EXPORTS是被定義了的,如圖:

所以使用dllexport,而在別的Project中,則使用dllimport。在CallDllTest中include這個lib.h,就可以了,當然你也可以寫得更好,我這里僅僅是demo。

四、DLL中的main函數(shù)

大家都知道C語言的程序是從main開始的,到了Windows環(huán)境下,則換成了WinMain,但也差不多,那DLL有沒有類似的入口呢?答案是肯定的,我們來改一下DllTest的lib.cpp。

lib.cpp

#include "lib.h"
#include 
"windows.h"
#include 
"stdio.h"

BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    
switch (ul_reason_for_call)
    {
    
case DLL_PROCESS_ATTACH:
  printf(
"\nprocess attach of DLL");
  
break;
    
case DLL_THREAD_ATTACH:
  printf(
"\nthread attach of DLL");
  
break;
    
case DLL_THREAD_DETACH:
  printf(
"\nthread detach of DLL");
  
break;
    
case DLL_PROCESS_DETACH:
  printf(
"\nprocess detach of DLL");
  
break;
    }
    
return TRUE;
}

int add(int x,int y)
{
    
return x + y;
}

你能看到一個叫“DllMain”的函數(shù),它就是dll的入口,oh,當然了,我這篇文章所講的都是針對Windows操作系統(tǒng)的,Linux的可不一樣哦,甚至一般來說,Linux的DLL都不叫“DLL”。

好了,你再按照前面的方法去調(diào)用下這個DLL,(記得拷貝這個dll到相應(yīng)目錄去)這時候你就能看到執(zhí)行結(jié)果中多了“process attach of DLL”和“process detach of DLL”,這是很顯而易見的,一個進程連接和斷開連接到這個dll的時候,DllMain就會被調(diào)用,且傳遞的ul_reason_for_call參數(shù)分別是DLL_PROCESS_ATTACH和DLL_PROCESS_DETACH,那什么時候會有“DLL_THREAD_ATTACH”和“DLL_THREAD_DETACH”?當庫已經(jīng)加載,創(chuàng)建新的線程和銷毀線程的時候,會分別使用THREAD_ATTACH和THREAD_DETACH參數(shù)來調(diào)DllMain。

五、調(diào)用方式

前面我們導(dǎo)入,導(dǎo)出函數(shù)的時候都加了一個“extern "C"”,那不加會怎么樣呢?如果再涉及到這幾個修飾符:__stdcall,__cdecl和__fastcall,那又會怎樣呢?我畫了兩個表,大家可以比較下,體會下。

這是三種不同調(diào)用方式的比較:

這是命名修飾在不同方式下的比較:

如果dll和exe的命名理解不一致,就有可能出錯。通常來說,我是習(xí)慣于用“extern "C"”和“__cdecl”的組合。

六、導(dǎo)出變量

前面只說了如何導(dǎo)出函數(shù),那如何導(dǎo)出一個變量呢?方法類似,甚至可以說幾乎一樣,看代碼:

lib.cpp

#include "lib.h"
#include 
"windows.h"
#include 
"stdio.h"

int iExportInt;

BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    
switch (ul_reason_for_call)
    {
    
case DLL_PROCESS_ATTACH:
  iExportInt 
= 112;
  
break;
    }
    
return TRUE;
}

lib.h

#ifndef LIB_H
#define LIB_H
#ifdef DLLTEST_EXPORTS
extern "C" int __declspec(dllexport) iExportInt;
#else
extern "C" int __declspec(dllimport) iExportInt;
#endif
#endif

這樣,就可以了,和導(dǎo)出函數(shù)是沒什么差別吧?同樣,你也可以用Depends觀察生成的DLL,你會發(fā)現(xiàn)iExportInt這個導(dǎo)出符號,也就是我們導(dǎo)出的這個變量了。現(xiàn)在看CallDllTest的代碼:

CallDllTest.cpp

#include "stdafx.h"
#include 
"lib.h"

#pragma comment(lib, 
"dllTest.lib")

int main(int argc, char* argv[])
{
 printf(
"%d\n", iExportInt);
 iExportInt
++;
 printf(
"%d\n", iExportInt);
 
return 0;
}

輸出是什么?112和113,說明成功了。不知道你這個時候有沒有想到一個問題,那就是如果兩個進程同時調(diào)用dllTest.dll,而且同時修改和讀取iExportInt,那會不會亂掉呢?要不要做一個互斥鎖呢?答案是:不會,不需要。這得益于Windows內(nèi)存管理的一個底層實現(xiàn)技術(shù),叫Copy-on-write,在調(diào)用執(zhí)行“iExportInt++”的時候,其實并非真正修改了DLL中的值,而是做了一份拷貝,通過內(nèi)存映射機制,使得程序訪問的那個“iExportInt”其實是那份拷貝,而另一進程使用的也是自己的拷貝,互不干涉。

七、共享內(nèi)存

緊接著前面這個問題,那如果我企圖通過DLL來讓不同進程共享一段內(nèi)存,而不是讓系統(tǒng)執(zhí)行默認的Copy-on-write操作,那怎么辦呢?有辦法!這是Microsoft提供的一個方法,個人覺得是個不錯的進程間通信的方法,比如兩個進程需要交換一大塊數(shù)據(jù),而且這一大塊數(shù)據(jù)變化比較頻繁,通過數(shù)據(jù)庫啊,文件啊,就顯得有點慢,如果通過socket啊,管道啊,就顯得有些不直接,還是直接使用共享內(nèi)存來得直接,但很多人并不知道這個功能,我這里跟大家分享下。

lib.h

#ifndef LIB_H
#define LIB_H
#ifdef DLLTEST_EXPORTS
extern "C" __declspec(dllexport) unsigned char dataChunk[100000];
#else
extern "C" __declspec(dllimport) unsigned char dataChunk[100000];
#endif
#endif

lib.cpp

#include "lib.h"

#pragma data_seg(
"shared")
unsigned 
char dataChunk[100000]={0};
#pragma data_seg()

#pragma comment(linker, 
"/SECTION:shared,RWS")

Build一下,然后用Depends看看輸出情況。現(xiàn)在來改CallDllText.cpp。這里有非常要注意的兩個地方,一是“={0}”這個初始化,這是必須的,否則共享將不起作用,Microsoft規(guī)定了共享段一定需要先初始化,哪怕只是給第一個元素賦個隨便什么值都好,如這個例子,我只是給第一個元素賦值了個0;另一處要注意的是“/SECTION:shared,RWS"這個字符串,中間可別要有空格,否則你同樣會發(fā)現(xiàn)共享不起作用,我當時調(diào)試就很郁悶,因為我習(xí)慣在英文逗號后加個空格。

CallDllText.cpp

#include "stdafx.h"
#include 
"windows.h"
#include 
"lib.h"

#pragma comment(lib, 
"dllTest.lib")

int main(int argc, char* argv[])
{
 printf(
"%d\n", dataChunk[0]++);
 Sleep(
10000);
    
return 0;
}

Sleep(10000)會讓程序堵塞10秒鐘,這樣就可以運行多個程序的副本,來觀察共享的效果。

八、結(jié)束

DLL涵蓋的知識面相當廣,本文只是篇入門級的文章,介紹了一些比較實用的內(nèi)容而已,如果要進一步學(xué)習(xí),需要看看《Windows核心編程》這種經(jīng)典著作,關(guān)于DLL的很多內(nèi)容我都沒有提及到,比如DLL的導(dǎo)出方法其實有好幾種,我介紹的只是其中一種,但我認為我介紹的方法是最好用而且是最簡單的。我們寫程序,是為了實現(xiàn)某些應(yīng)用,而不是為了炫耀某些技術(shù),所以我是偏向于使用成熟,可靠和易行的方法。

posted on 2009-09-24 16:35 Jiang Guogang 閱讀(664) 評論(0)  編輯 收藏 引用 所屬分類: Windows Programming
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美私人啪啪vps| 亚洲一区国产一区| 亚洲无线视频| 亚洲一级黄色av| 欧美一级专区免费大片| 欧美一级网站| 裸体丰满少妇做受久久99精品 | 亚洲国产精品www| 亚洲国产天堂久久综合| 亚洲国产精品第一区二区| 日韩视频在线你懂得| 亚洲一区二区三区免费视频| 欧美在线观看网址综合| 蜜桃精品一区二区三区| 亚洲另类一区二区| 亚洲欧美日韩国产成人精品影院| 久久精品国产亚洲精品| 欧美人与禽猛交乱配| 国产麻豆9l精品三级站| 亚洲国产精品久久久久秋霞蜜臀| 中文亚洲视频在线| 久久人体大胆视频| 艳女tv在线观看国产一区| 久久精品亚洲| 欧美天天在线| 亚洲黄色成人| 久久精品国产免费| 一本色道久久综合狠狠躁的推荐| 久久福利精品| 国产精品v亚洲精品v日韩精品| 黑丝一区二区三区| 午夜欧美精品久久久久久久| 亚洲国产欧美不卡在线观看| 一区二区三区国产精华| 男人的天堂成人在线| 国内精品伊人久久久久av影院 | 亚洲一级一区| 欧美顶级大胆免费视频| 午夜精品久久久久影视| 欧美日韩国产在线看| 亚洲激情一区二区| 久久久久久伊人| 亚洲伊人一本大道中文字幕| 欧美久久九九| 亚洲精品乱码久久久久久蜜桃麻豆| 久久久91精品国产| 午夜久久99| 国产精品高清在线| 中日韩美女免费视频网站在线观看| 欧美va亚洲va日韩∨a综合色| 欧美一进一出视频| 国产欧美日韩激情| 欧美在现视频| 欧美在线免费视屏| 国产一区二区剧情av在线| 午夜在线视频观看日韩17c| 这里只有精品在线播放| 欧美色视频在线| 亚洲一区中文| 亚洲午夜精品久久久久久app| 欧美三级日本三级少妇99| 亚洲视频专区在线| 一区二区三区国产在线| 国产精品嫩草99av在线| 亚洲欧美一级二级三级| 亚洲欧美国产毛片在线| 国产日产精品一区二区三区四区的观看方式| 亚洲欧美另类中文字幕| 亚洲欧美日韩久久精品| 国内综合精品午夜久久资源| 蜜臀va亚洲va欧美va天堂| 男女激情久久| 亚洲欧美日韩成人高清在线一区| 亚洲综合国产| 国产亚洲成av人在线观看导航| 久久婷婷激情| 欧美大片第1页| 亚洲自啪免费| 久久精品91久久香蕉加勒比| 亚洲人成小说网站色在线| 亚洲美女精品成人在线视频| 国产精品久久久久久久久免费| 久久精品日韩欧美| 欧美成人69| 欧美在线看片a免费观看| 久久精品国产清自在天天线| 中日韩美女免费视频网站在线观看| 午夜影院日韩| 亚洲欧洲日韩女同| 亚洲视频免费| 亚洲国产精品悠悠久久琪琪| 一级日韩一区在线观看| 韩国在线一区| 99精品国产一区二区青青牛奶| 国产亚洲一级高清| 亚洲精品久久久久| 国产日韩欧美不卡| 91久久亚洲| 欧美有码在线观看视频| 欧美高潮视频| 欧美在线1区| 欧美精品1区| 久久琪琪电影院| 国产精品高清在线| 亚洲第一区在线| 国产一区二区三区久久精品| 日韩一区二区久久| 亚洲国产激情| 欧美亚洲免费| 午夜精品短视频| 欧美日韩成人综合天天影院| 欧美mv日韩mv国产网站| 国产麻豆精品久久一二三| 亚洲精品老司机| 亚洲国产影院| 久久久精品久久久久| 欧美在线在线| 国产精品久久久久免费a∨| 亚洲激情在线激情| 在线日韩中文字幕| 欧美一二三视频| 欧美一区视频| 国产精品美女在线| 一本色道久久综合亚洲精品不| 亚洲精品综合精品自拍| 毛片精品免费在线观看| 久久先锋资源| 国产在线精品自拍| 亚洲欧美日韩综合一区| 亚洲免费小视频| 欧美日韩在线播放| 日韩视频免费观看高清在线视频| 亚洲精品中文字幕女同| 欧美插天视频在线播放| 亚洲福利视频网| 亚洲人成在线观看一区二区| 欧美aⅴ一区二区三区视频| 欧美成人一区二区在线| 亚洲激情在线观看| 欧美国产先锋| 亚洲免费精品| 午夜在线精品| 在线观看日韩欧美| 欧美1区2区| 99精品国产高清一区二区| 欧美一区二区成人| 国产自产2019最新不卡| 久久综合九色综合欧美就去吻 | 欧美黄色网络| 99re66热这里只有精品4| 亚洲午夜极品| 国产欧美日韩免费看aⅴ视频| 久久精品国产69国产精品亚洲| 免费在线日韩av| 99re66热这里只有精品4| 国产精品久久久久一区二区| 欧美一区三区三区高中清蜜桃| 蜜桃av久久久亚洲精品| 一本色道久久综合| 国产精品色在线| 久久网站热最新地址| 99精品国产高清一区二区| 久久经典综合| 亚洲国产一区二区三区a毛片| 国产无一区二区| 国产精品视频免费一区| 欧美在线地址| 亚洲黄色影院| 亚洲欧美激情精品一区二区| 亚洲第一黄色| 国产精品美女一区二区| 欧美aaa级| 久久成人综合网| 一本久久a久久免费精品不卡 | 一本高清dvd不卡在线观看| 久久久99爱| 在线一区免费观看| 精品成人国产| 国产精品无码永久免费888| 免费的成人av| 欧美在线电影| 一本久久综合亚洲鲁鲁| 免费日韩一区二区| 欧美一区二区三区免费看| 99精品视频网| 亚洲黄色有码视频| 尤物yw午夜国产精品视频| 国产精品影音先锋| 欧美日本韩国一区二区三区| 久久精品夜色噜噜亚洲a∨| 亚洲专区一二三| 日韩一级免费| 亚洲黄一区二区三区| 麻豆精品91| 久久精品国产在热久久| 亚洲欧美日韩综合aⅴ视频| 日韩午夜在线电影| 亚洲国产精彩中文乱码av在线播放| 国产一区二区日韩| 国产精品久久久久久久久久久久久 |