<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    __declspec(dllimport)的作用

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    是時候總結一下__declspec(dllimport)的作用了。可能有人會問:__declspec(dllimport)和__declspec(dllexport)是一對的,在動態鏈接庫中__declspec(dllexport)管導出,__declspec(dllimport)管導出,就像一個國家一樣,有出口也有進口,有什么難理解的呢?這是一種很自然的思路,開始我也是這樣理解。


    但是在兩年前的一個項目中,我發現不用__declspec(dllimport)似乎也可以。比如現在我新建一個使用共享MFC DLL的規則DLL工程:DllDlg。然后我新建兩個文件:DllApi.h和DllApi.cpp。DllApi.h作為接口文 件,DllApi.cpp作為實現文件。


    接著在DllApi.h聲明一個函數:

    [cpp] view plaincopy
    1. __declspec(dllexport) void HelloWorld();
    [cpp] view plaincopy
    1. __declspec(dllexportvoid HelloWorld();  


    在DllApi.cpp寫這個函數的實現:


    [cpp] view plaincopy
    1. void HelloWorld()
    2. {
    3. AfxMessageBox(_T("HelloWorld"));
    4. }
    [cpp] view plaincopy
    1. void HelloWorld()  
    2. {  
    3.     AfxMessageBox(_T("HelloWorld"));  
    4. }  


    這樣外部的應用程序或dll就能調用HelloWorld函數。這里要特別提醒的是:有些網友說要把DllApi.h中的__declspec(dllexport) void HelloWorld();改為__declspec(dllimport) void HelloWorld();才能提供給外部調用,實際上這并不需要,這個我已經測試過。從那時我就產生一個疑問:照這樣,像類似下面的:


    [cpp] view plaincopy
    1. #ifdef _EXPORTING
    2. #define API_DECLSPEC __declspec(dllexport)
    3. #else
    4. #define API_DECLSPEC __declspec(dllimport)
    5. #endif
    [cpp] view plaincopy
    1. #ifdef _EXPORTING  
    2. #define API_DECLSPEC    __declspec(dllexport)  
    3. #else  
    4. #define API_DECLSPEC    __declspec(dllimport)  
    5. #endif  

    是不是就只剩下一種作用:讓外部調用者看得更自然些,知道哪些接口是自己工程需要導入的?__declspec(dllimport)是不是一點實際作用都沒有呢?這個疑問一直盤旋在我的腦海。直到最近,我在CSDN論壇上發了一個帖子:


    __declspec(dllimport) 的作用到底在哪里呢?

    總結了各位大蝦的發言,特得出如下結論:

    1. 在導入動態鏈接庫中的全局變量方面起作用:
    使用類似

    [cpp] view plaincopy
    1. #ifdef _EXPORTING
    2. #define API_DECLSPEC __declspec(dllexport)
    3. #else
    4. #define API_DECLSPEC __declspec(dllimport)
    5. #endif
    [cpp] view plaincopy
    1. #ifdef _EXPORTING  
    2. #define API_DECLSPEC    __declspec(dllexport)  
    3. #else  
    4. #define API_DECLSPEC    __declspec(dllimport)  
    5. #endif  


    可以更好地導出dll中的全局變量,比如按照的宏,可以在dll中這樣導出全局變量:


    [cpp] view plaincopy
    1. API_DECLSPEC CBtt g_Btt;
    [cpp] view plaincopy
    1. API_DECLSPEC CBtt g_Btt;  


    然后在調用程序這樣導入:


    [cpp] view plaincopy
    1. API_DECLSPEC CBtt g_Btt;
    [cpp] view plaincopy
    1. API_DECLSPEC CBtt g_Btt;  


    當然也可以使用extern關鍵字,比如在dll中這樣導出全局變量:


    [cpp] view plaincopy
    1. CBtt g_Btt;
    [cpp] view plaincopy
    1. CBtt g_Btt;  


    然后在調用程序這樣導入:


    [cpp] view plaincopy
    1. extern CBtt g_Btt;
    [cpp] view plaincopy
    1. extern CBtt g_Btt;  


    但據說使用__declspec(dllimport)更有效。


    2. __declspec(dllimport)的作用主要體現在導出類的靜態成員方面,
    比如在動態鏈接庫中定義這樣一個導出類:


    [cpp] view plaincopy
    1. class __declspec(dllexport) CBtt
    2. {
    3. public:
    4. CBtt(void);
    5. ~CBtt(void);
    6. public:
    7. CString m_str;
    8. static int GetValue()
    9. {
    10. return m_nValue;
    11. }
    12. private:
    13. static int m_nValue;
    14. };
    [cpp] view plaincopy
    1. class __declspec(dllexport) CBtt  
    2. {  
    3. public:  
    4.     CBtt(void);  
    5.     ~CBtt(void);  
    6. public:  
    7.     CString m_str;  
    8.     static int GetValue()  
    9.     {  
    10.         return m_nValue;  
    11.     }  
    12. private:  
    13.     static int m_nValue;  
    14. };  


    照上面這樣聲明,外部雖然可以使用CBtt類,但不能使用CBtt類的GetValue函數,一使用就會出現無法解析的外部符號 "public: static int CBtt::m_nValue" (?m_nValue@CBtt@@2HA)。只有如下聲明才能使用CBtt類的GetValue函數:


    [cpp] view plaincopy
    1. #ifdef _EXPORTING
    2. #define API_DECLSPEC __declspec(dllexport)
    3. #else
    4. #define API_DECLSPEC __declspec(dllimport)
    5. #endif
    6. class API_DECLSPEC CBtt
    7. {
    8. public:
    9. CBtt(void);
    10. ~CBtt(void);
    11. public:
    12. CString m_str;
    13. static int GetValue()
    14. {
    15. return m_nValue;
    16. }
    17. private:
    18. static int m_nValue;
    19. };
    [cpp] view plaincopy
    1. #ifdef _EXPORTING  
    2. #define API_DECLSPEC    __declspec(dllexport)  
    3. #else  
    4. #define API_DECLSPEC    __declspec(dllimport)  
    5. #endif  
    6. class API_DECLSPEC CBtt  
    7. {  
    8. public:  
    9.     CBtt(void);  
    10.     ~CBtt(void);  
    11. public:  
    12.     CString m_str;  
    13.     static int GetValue()  
    14.     {  
    15.         return m_nValue;  
    16.     }  
    17. private:  
    18.     static int m_nValue;  
    19. };  



    3. 使用隱式使用dll時,不加__declspec(dllimport)完全可以,使用上沒什么區別,只是在生成的二進制代碼上稍微有點效率損失。


    a、 不加__declspec(dllimport)時,在使用dll中的函數時,編譯器并不能區別這是個普通函數,還是從其它dll里導入的函數,所以其生 成的代碼如下:

    call 地址1

    地址1:
    jmp 實際函數地址


    b、有 __declspec(dllimport)時,編譯器知道這是要從外部dll導入的函數,從而在生成的exe的輸入表里留有該項,以便在運行 exe,PE載入器加載exe時對輸入地址表IAT進行填寫,這樣生成的代碼如下:

    call dword ptr[輸入表里哪項對應的內存地址] (注意:現在就不需要jmp stub了)。這里
    有興趣的朋友可以參看《編譯原理》和 PE文件格式。


    4.使用__declspec(dllimport)體現了語言的一種對稱美,比如雖然!true就是表示false,但是我們還是需要false這個關鍵字,這里體現了一種對稱美。

    在此特別感謝CSDN的眾位大俠:superdiablo、wltg2001、ccpaishi、jszj、WizardK、hurryboylqs、jingzhongrong、jameshooo、glacier3d、winnuke、starnight1981、laiyiling、yang79tao、ForestDB、zhouzhipen、lxlsymbome、Beyond_cn。


    參考文獻:


    1. __declspec(dllimport) 到底有什么用?



    from: http://blog.csdn.net/clever101/article/details/5421782

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全