| DLL“地獄”的原因及其解決方案 本文將要介紹DLL的向后兼容性問題,也就是著名的“DLL Hell”問題 本文將要介紹DLL的向后兼容性問題,也就是著名的“DLL Hell”問題。首先我會列出自己的研究結(jié)果,其中包括其它一些研究者的成果。在本文的最后,我還將給出“DLL Hell”問題的一個解決方案。 介紹 我曾經(jīng)接受過一個任務,去解決一個DLL版本更新的問題————某個公司給用戶提供了一套SDK,這個SDK是由一系列DLL組成的;DLL中導出了很多類,用戶使用這些類(直接使用或派生新的子類)來繼續(xù)他們的C++程序開發(fā)。用戶在使用這些DLL時沒有得到很詳細的使用說明(比如使用這些DLL中導出的類有什么限制等)。當這些DLL更新為新的版本之后,他們發(fā)現(xiàn)他們開發(fā)的基于這些DLL的應用程序會經(jīng)常崩潰(他們的應用程序從SDK的導出類派生了新的子類)。為了解決這個問題,用戶必須重新編譯他們的應用程序,重新連接新版本的SDK DLL。 我將對這個問題給出我的研究結(jié)果,同時還有我從其它地方搜集過來的相關(guān)信息。最后,我將來解決這個“DLL Hell”問題。 研究結(jié)果 就我個人的理解,這個問題是由SDK DLL中導出的基類改動之后引起的。我查看了一些文章后發(fā)現(xiàn),DLL的向后兼容性問題其實早有人提出。但作為一個實在的研究者,我決定自己做一些試驗。結(jié)果,我發(fā)現(xiàn)如下的問題: 1. 在DLL的導出類中增加一個新的虛函數(shù)將導致如下問題: ?。?)如果這個類以前就有一個虛函數(shù)B,此時在它之前增加一個新的虛函數(shù)A。這樣,我們改變了類的虛函數(shù)表。于是,表中的第一個函數(shù)指向了函數(shù)A(而不是原來的B)。此時,客戶程序(假設(shè)沒有在拿到新版本的DLL之后重新編譯、連接)調(diào)用函數(shù)B就會產(chǎn)生異常。因為此時調(diào)用函數(shù)B實際上轉(zhuǎn)向了調(diào)用函數(shù)A,而如果函數(shù)A和函數(shù)B的參數(shù)類型、返回值類型迥異的話問題就出來了! ?。?)如果這個類原本沒有虛函數(shù)(它的父類也沒有虛函數(shù)),那么給這個類增加一個新的虛函數(shù)(或者在它的父類增加一個虛函數(shù))將導致新增加一個類成員,這個成員是一個指針類型的,指向虛函數(shù)表。于是,這個類的尺寸將會被改變(因為增加了一個成員變量)。這種情況下,客戶程序如果創(chuàng)建了這個類的實例,并且需要直接或間接修改類成員的值的時候就會有問題了。因為虛函數(shù)表的指針是作為類的第一個成員加入的,也就是說,原本這個類定義的成員因為虛函數(shù)表指針的加入而都產(chǎn)生了地址的偏移??蛻舫绦?qū)υ蓡T的操作自然就出現(xiàn)異常了。 ?。?)如果這個類原本就有虛函數(shù)(或者只要它的父類有虛函數(shù)),而且這個類被導出了,被客戶程序當作父類來用。那么,我們不要給這個類增加虛函數(shù)!不僅在類聲明的開頭不能加,即使在末尾處也不能加。因為加入虛函數(shù)會導致虛函數(shù)表內(nèi)的函數(shù)映射產(chǎn)生偏移;即使你將虛函數(shù)加在類聲明的末尾,這個類的派生類的虛函數(shù)表也會因此產(chǎn)生偏移。 2. 在DLL的導出類中增加一個新的成員變量將導致如下問題: (1)給一個類增加一個成員變量將導致類尺寸的改變(給原本有虛函數(shù)表的類增加一個虛函數(shù)將不會改變類的尺寸)。假設(shè)這個成員增加在類聲明的最后。如果客戶程序為創(chuàng)建這個類的實例少分配了內(nèi)存,那么可能在訪問這個成員時導致內(nèi)存越界。 ?。?)如果在原有的類成員中間增加一個新的成員,情況會更糟糕。因為這樣會導致原有類成員的地址產(chǎn)生偏移??蛻舫绦虿僮鞯氖且粋€錯誤的地址表,對于新成員后面的成員尤其是這樣(它們都因為新成員的加入而導致了自己在類中的偏移的變化)。 ?。ㄗⅲ荷鲜龅目蛻舫绦蚓褪侵甘褂肧DK DLL的應用程序。) 除了上面這些原因外,還有其它操作會導致DLL的向后兼容性問題。下面列出了解決(大部分)這些問題的方法。 | 
|  | 
來自: bluecrystal > 《vc的DLL》