• <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>

            山寨:不是最好的,是最適合我們的!歡迎體驗山寨 中文版MSDN

            Blog @ Blog

            當華美的葉片落盡,生命的脈絡才歷歷可見。 -- 聶魯達

            常用鏈接

            統計

            積分與排名

            BBS

            Blog

            Web

            最新評論

            VC之DLL編程

            DLL編程

            靜態鏈接:每個應用程序使用函數庫,必須擁有一份庫的備份。多個應用程序運行時,內存中就有多份函數庫代碼的備份。

            動態連接庫:多個應用程序可以共享一份函數庫的備份。

             

            DLL的調用方式:DLL的使用者在調用庫中輸出函數時,函數參數的壓棧和出棧順序和方法。

            VC++支持四種方式:

            <1>_cdecl調用方式: 也叫C調用方式,函數參數的壓棧順序是從右至左,參數的出棧方式由調用者完成,在調用DLL的函數的地方都應包含清空堆棧的代碼,它是C/C++缺省的調用方式。

            <2>_stdcall標準調用方式:函數參數壓棧順序是從右至左,參數出棧工作由被調用者負責完成。系統將加在函數原型定義前的”WINAPI”宏翻譯為適當的調用方式,對于Win32_stdcall調用方式。

            <3>_fastcall:主要特點是調用速度快,被調用的函數參數傳遞不依靠堆棧,而是通過寄存器,但并不是對所有的參數傳遞均使用寄存器,往往只是用ECXEDX傳送前兩個雙字或比較小的參數,其余的參數傳遞仍然采用從右至左壓棧方式,出棧工作由被調用的函數完成。

            <4>thiscall:前三種是關鍵字,可以加到函數前作修飾,thiscall不是關鍵字,因此程序中不能顯式寫入,這種方式僅應用于C++成員函數,thisC++中指向對象的指針,this存放在ECX寄存器中,參數從右至左壓棧,出棧由被調用者完成。

             

            DLL的入口函數

            DllMain()函數負責完成DLL的初始化和解說DLL調用后的清理工作。當加載DLL時,如存在DllMain()函數則調用它。

             

            MFC DLL

              MFC DLL可以讓我們的程序使用MFC庫,它分為3類:

            <1>Regular Dll with MFC Statically linked   (正規)

                 靜態鏈接MFC庫,在DLL工程中將包含工程中所需的MFC庫代碼的拷貝,因此,程序可以脫離MFC庫使用。

            <2>Regular Dll using shared MFC Dll        (正規)

                 動態共享MFC庫,工程必須在裝有MFC庫的機器上才能運行。

            MFC正規DLL編寫注意問題:

                 應在輸出函數的函數體內首先加入:

                 AFX_MANAGE_STATE(AfxGetStaticModuleState());

            <3>MFC Extension Dll(using shared MFC Dll)     (擴展)

                 它不但能輸出函數,還能輸出類,用戶可以直接使用、繼承這個輸出類,但它不是正規DLL,如果要讓非VC++程序調用,必須使用正規DLL

            MFC擴展DLL編寫注意問題:

                 <1>在要輸出的類定義中加入:AFC_EXT_CLASS

                     如:class AFX_EXT_CLASS  cls{};

                 <2>在要輸出的函數定義前加入:AFC_EXT_CLASS

                     如:AFX_EXT_CLASS int  func(){}

             

            自行編寫DLL的方法

                <1>DLL中編寫的函數前加上”__declspec(dllexport)”即可導出該函數。

            <2>DLL中導出類,是在class和類名之間加入”__declspec(dllexport)”,如果只想導出類中指定的函數,可只在該函數前加上”__declspec(dllexport)”

            <3>C++為支持函數重載,采用了名稱壓軋,因此,DLL文件在編譯時,函數名會發生改變,為保證對DLL的正確訪問,可在”__declspec(dllexport)”聲明之前加入”extern “c””,編譯時就不會發生名稱改變,但extern “c”只能用于導出全局函數,不能導出類的成員,如果在函數名前加入了調用約定(如:_stdcall),編譯時還是會發生名稱改變。

                     也可通過模塊定義文件的方式解決名稱改變的問題,模塊定義文件的后綴為”.def”,步驟如下:

                     1新建一個文本文檔,改名為”x.def”

                     2x.def加入到工程;

            3編輯x.defEXPORTS下所寫函數名如與DLL文件中函數名相同,則以所寫名稱導出該函數。

                <4>DLL通過GetForegroundWindow()獲得正在使用它的前景窗口的句柄。

                <5>GetModuleHandle()得到一個DLL的句柄。

                    GetSystemMetrics()獲取系統信息。

             

            系統對DLL中可改變的數據,在進程寫訪問時會拷貝到一個新的數據頁面,如果多個進程要共享該數據,可設置節,創建節后,將數據放到節中且必須初始化:

            #pragma     data_seg(“name”)          //開頭

                //數據

            #pragma     data_seg()      //結尾

            #pragma     comment(linker,”/section:name,RWS”)

                //設為讀、寫、共享,也可寫在.def文件中。

             

            使用DLL

                要使用DLL,首先要將DLL文件映像到用戶進程的地址空間中,并聲明被調用的函數,然后才能進行函數調用,調用方法與一般函數相同。

                DLL映像到進程地址空間的方法:

                <1>隱式的加載時鏈接

                    DLL工程經編譯后,產生一個.dll文件,一個.lib文件及一個包含DLL輸出函數聲明的.h頭文件,隱式調用DLL就是將這個.lib文件鏈接到工程中。

                    lib文件中包含了DLL允許調用的所有函數列表,鏈接器發現程序調用了lib文件中列出的某個函數時,會在程序的可執行文件的文件映像中加入包含這個函數的DLL文件的名字信息,當程序運行時,可執行文件被操作系統產生映像文件,系統會查看這個映像文件中關于DLL的信息,然后將這個DLL文件映像到進程的地址空間。

                鏈接lib文件的方法:

            1加入到文件列表

            2Link項下加入

            3#pragma   comment(lib,”mydll.lib”)

            <2>顯式的運行時鏈接步驟如下:

            1LoadLibrary()AfxLoadLibrary()加載DLL或可運行模塊;

            2GetProcAddress()得到要調用的DLL中函數的指針,然后使用該函數;

            3使用完DLL以后,用FreeLibrary()DLL在進程的映射解除,減少加載DLL的記數。

                被調用的函數聲明的方法有三種:

                <1>”extern”聲明被調用函數。

                <2>使用”__declspec(dllimport)”聲明,即告訴編譯器,所引用的函數或文件是從DLL中輸入的,編譯器能生成運行效率更高的代碼。

                <3>也可將聲明放在DLL編寫的頭文件中,在使用的文件中包含該頭文件即可。

             

             

            要使用DLL中導出的類,必須在使用的文件中包含該類所在的頭文件!

            盡量導出方法(做接口)少導出類。

            標準DLL中導出函數的寫法:

            extern "C"  BOOL __declspec(dllexport) EXPORT ShowDlg()   ///標準導出函數格式

            {

                AFX_MANAGE_STATE(AfxGetStaticModuleState());//些宏不可少!

                // 此處為普通函數體

            }

            1.AfxGetStaticModuleState()指向當前模塊狀態;

            2.當前函數調用結束后原模塊的狀態自動被恢復;

            3.用于DLL中所調用MFC函數、類、資源時的模塊狀態切換

            并在def文件中定義導出函數的序號:ShowDlg @1

            在調用處寫如下代碼:

            typedef void (*dllfun)(); //定義函數指針類型

            HINSTANCE   hlib= NULL;

            hlib=LoadLibrary("std_dll.dll"); //加載庫

            dllfun  ShowDlg  = NULL;//定義函數指針

            ShowDlg=(dllfun)GetProcAddress(hlib,"ShowDlg");//獲取庫中函數地址

            ShowDlg();  //調用函數

             

             

            擴展DLL導出類的寫法:

            class AFX_EXT_CLASS  clsName{};

            擴展DLL中的資源使用

            簡單的說:每個DLL有自己特有的資源。在使用時,明確的告訴系統要使用哪個DLL的資源。現在的問題就是如何告訴系統使用哪個DLL的資源。函數:AfxSetResourceHandle() 可以完成這個功能。參數是資源的句柄。

            那怎么得到某個DLL的資源句柄呢?如下:

            在擴展DLL的入口函數

            extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)

             {

            if (!AfxInitExtensionModule(ShpSymbolDLL, hInstance))

                   return 0;

            }

            其中ShpSymbolDll 可能會因工程名不同而不同,這里就以這個名稱代替來說明了,DLL的資源句柄就可以在此得到。

             ShpSymbolDLL 定義:

             AFX_EXTENSION_MODULE ShpSymbolDLL  = { NULL, NULL };

            ShpSymbolDLL.hResource 這個就是我們要的了。其它參數請看說明。現在我們在使用某DLL的資源時只要先加入以下兩行就可以正確執行了:

            HINSTANCE hOld = AfxGetResourceHandle();

            AfxSetResourceHandle( ShpSymbolDLL.hResource );

            注意在用完之后再恢復:

            AfxSetResourceHandle( hOld );

            另外一個不得不提起的東西,在入口函數中有一行

            new CDynLinkLibrary(ShpSymbolDLL);

            旁邊有一說明:將此 DLL 插入到資源鏈中。

            的確如此。言下之意,上面所說的沒什么用了?其實不然,假如DLL中有一個Dialog ID120,在你調用此DLL的應用程序資源中,如果沒有ID的值為120。那么,上面的都是白做了,你會得到預料中的結果。但如果應用程序中有一相同ID的對話框資源呢?請大家一試。結果就不一樣了。其中的原因與new CDynLinkLibrary(ShpSymbolDLL) 相關聯。

            具體請看MFC中 的代碼 DoModal() 就會得到解答。或看MSDN中帶的例子 dllhusk,系統自動會查找相應的資源,但不會判斷哪個是正確的。以找到的第一個資源為準。

            另:為了編寫方便,可以寫一個類 ,寫成全局的。

            class CModuleInfo

            {public:

               HMODULE    m_hModule;

               HMODULE    m_hResource;

             public:

               CModuleInfo(void){}

               ~CModuleInfo(void){}

             };

            class AFX_EXT_CLASS CModuleStateMana

            {

               HINSTANCE m_hInstOld;

             public:

               CModuleStateMana();

               ~CModuleStateMana();

            };

            實現如下:

             CModuleInfo  s_mi;

             CModuleStateMana::CModuleStateMana()

            {

               m_hInstOld = AfxGetResourceHandle();

               AfxSetResourceHandle( s_mi.m_hModule );

             }

            CModuleStateMana::~CModuleStateMana()

            {

               AfxSetResourceHandle( m_hInstOld );

            }

            然后在入口函數之前加入

            extern CModuleInfo s_mi;

            函數中加入:

                 s_mi.m_hModule   = ShpSymbolDLL.hModule;

                 s_mi.m_hResource= ShpSymbolDLL.hResource;

            在調用的時候只要先加入:

             CModuleStateMana msm;

            就可以正確調用了。

            posted on 2008-06-20 14:07 isabc 閱讀(896) 評論(0)  編輯 收藏 引用 所屬分類: C++基礎

            廣告信息(免費廣告聯系)

            中文版MSDN:
            歡迎體驗

            久久人人添人人爽添人人片牛牛| 97久久香蕉国产线看观看| 国内高清久久久久久| 久久精品国产亚洲77777| 93精91精品国产综合久久香蕉| 久久Av无码精品人妻系列| 天天久久狠狠色综合| 精品人妻伦九区久久AAA片69 | 情人伊人久久综合亚洲| 久久精品免费全国观看国产| 日本免费一区二区久久人人澡 | 亚洲精品白浆高清久久久久久| 亚洲天堂久久精品| 97精品国产97久久久久久免费| 国产激情久久久久影院老熟女免费| 精品国产乱码久久久久软件| 久久久久亚洲爆乳少妇无| 久久发布国产伦子伦精品| 久久人人爽人人爽人人片av麻烦| 久久亚洲国产中v天仙www| 国产综合久久久久| 99精品久久精品一区二区| 香港aa三级久久三级老师2021国产三级精品三级在 | 婷婷久久综合九色综合98| 午夜不卡久久精品无码免费| 亚洲精品无码专区久久同性男| 99久久婷婷国产一区二区| 久久99国产精品久久99果冻传媒| 亚洲中文字幕久久精品无码喷水| 久久亚洲国产成人影院网站 | 日本强好片久久久久久AAA | 久久亚洲精精品中文字幕| 久久只有这里有精品4| 亚洲а∨天堂久久精品9966| 欧美一级久久久久久久大片| 三级片免费观看久久| 久久人人爽人人澡人人高潮AV| 色婷婷久久久SWAG精品| 伊人久久大香线蕉综合5g| 亚洲伊人久久综合中文成人网| 亚洲精品无码专区久久同性男|