2009-12-28 70 views
8

我們有很多產品,並且在每個產品的應用程序中都有一些常見的DLL。現在我們將每個常見的DLL複製到每個產品的bin目錄中,並將它們視爲私有程序集。這不必要地增加了每個產品的msi大小,並且當DLL發生問題時,我們必須構建包含DLL的每個產品的msi並部署它。從中央資源庫加載DLL的方法

是否有任何指示產品應用程序使用公用專用目錄來加載DLL [使用清單方案..]? [注:添加私有目錄PATH環境彷彿有使用相同名稱的DLL在系統目錄中不會提供一個解決方案,這將需要特權在我們的私人目錄]

-Kartlee

回答

1

如果你在談論.NET,您可以:

  • 使用Assembly.Load(byte[])
  • 直接從數據庫中加載你的DLL通過使用Assembly.TypeResolve事件
  • 通過使用TypeProvider
  • 通過在你的配置文件中定義的探針目錄

像:

<configuration> 
    <runtime> 
     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
      <probing privatePath="bin"/> 
     </assemblyBinding> 
    </runtime> 
</configuration> 
+0

感謝您的回覆。不幸的是,我正在尋找不使用任何運行時動態鏈接方法(如Loadlibrary(..))的C/C++應用程序。無論如何要通過清單來指導「探索」概念如何運作? – Kartlee 2009-12-28 14:45:56

+0

@Kartlee,對不起,我不瞭解C/C++;但我編輯了你的問題,以反映關鍵字 – 2009-12-28 14:50:12

0

我不知道如果這是你在找什麼,但是,我現在的工作,我們爲我們所有的DLL使用通用的UNC路徑。

我們有一個類似於...

\\ SERVER01 \ productionLibrary生產讀的DLL,每一個在它自己的目錄。

\\ SERVER01 \ developmentLibrary這反映生產庫,這是因爲他們開發的開發人員使用的。

當我們在測試完成後合併代碼時,我們將其部署到生產庫。所有項目在構建到MSI文件中供部署時參考生產庫。我們的自動化系統將項目構建到MSI中,並驗證所有DLL都指向生產庫,因此不可能意外地使用開發副本。

希望這會有所幫助。

0

我不知道我理解正確的問題,但如果您在使用.NET的時候,有一個全局程序集緩存(GAC):http://en.wikipedia.org/wiki/Global_Assembly_Cache

這緩存組件和允許他們通過應用程序的重用(與.net框架一樣)。您只需在安裝時將程序集註冊到GAC,例如提供所有常見程序集的「您的框架安裝」,並且只能部署一次。

+0

感謝您的回覆。請看我對魯本斯法里亞斯的評論。 – Kartlee 2009-12-28 14:47:45

7

您不指定您的環境是.NET還是直線Win32。

我假設它的Win32版本,因爲如果它的.NET這樣做的技術在全局程序集緩存等方面都更接近手。

在Win32而言,可以在以下兩種方式之一從共享位置加載的Dll:

  • 使用調用LoadLibrary有明確完整路徑。這意味着您不能使用靜態鏈接 - 所有產品中使用的所有dll函數都必須通過GetProcAddress訪問。你不能從通過LoadLibrary加載的DLL導入C++類 - 它們必須靜態鏈接才能工作,所以這種方法可能或不可行。編寫可以僞裝成dll接口的shim頭文件並且在每次調用時都會根據需要及時執行dll加載和GetProcAddress,這並不難。

  • 另一種選擇是將dll轉換成所謂的「並排組件」並將它們安裝到WinSxS存儲中。不要被這個大名字嚇倒。 「並排裝配」是指「一個Dll文件和帶有版本信息的清單文件」。 然後,每個應用程序都會將「強名稱」(包含版本信息)放入其應用程序清單中,以便使用它的每個dll,並且Win32 Dll加載程序將使用它從WinSxS存儲區中選擇正確的常用dll實例。其基本過程是在MSDN文章中描述Guidelines for Creating Side-by-side Assemblies


在Windows版本6.1及以上(在Windows Server 2008和諷刺的是名爲Windows 7)應用程序配置文件現在要做的支持Application Configuration Files

探測元件

這意味着您應該能夠爲包含要加載的dll程序集的文件夾提供路徑(相對於您的應用程序)。


好吧,我已經做了Windows 7的一些測試,這一點也適用:

假設你已經安裝在\ Program Files文件\ App1的應用app1.exe,依賴於一些常見的DLL「thedll。 DLL」

在應用程序文件夾(\ Program Files文件\應用1)創建一個文件App1.exe.config,並給它包含以下內容: -

<configuration> 
    <windows> 
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
     <probing privatePath="..\AcmeCommon"/> 
    </assemblyBinding> 
    </windows> 
</configuration> 

現在,創建一個名爲\方案F文件夾iles \ AcmeCommon,並在其中一個文件夾acme.thedll,並將該dll.dll複製到\​​ Program Files \ AcmeCommon \ acme.thedll

也在AcmeCommon \ acme.thedll中創建一個名爲acme.thedll.manifest的文件 - this將成爲集清單描述組件稱爲「acme.thedll」

acme.thedll.manifest的內容將是: -

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
    <assemblyIdentity name="acme.thedll" version="1.2.3.4" processorArchitecture="x86" type="win32"/> 
    <file name="thedll.dll"/> 
</assembly> 

現在我們有共同的DLL,在一個共同的位置,一個本地的sxs程序集。我們有應用程序,配置文件將在Windows 7和2008服務器(及以上)中告訴它在常用位置搜索程序集。但該應用程序仍然試圖鏈接到DLL作爲DLL,而不是通過組裝。

爲了讓應用程序加載程序集,我們需要嚮應用程序添加清單文件。如果您使用的是Visual Studio,那麼您的應用程序可能已經配置爲通過鏈接器和清單工具項目設置來創建和嵌入清單。在這種情況下,最簡單的方法,告訴應用程序有關的組件在項目中加入以下代碼到至少一個頁眉或C/CPP文件後重建它: -

#pragma comment(linker,"/manifestdependency:\"type='win32' name='acme.thedll' version='1.2.3.4' processorArchitecture='x86' language='*'\"") 

如果您使用的是老式當應用程序加載Win32加載器將加載:構建環境中,體現在手工製作,您將需要與在應用1文件夾app1.exe.manifest合併以下XML:

<dependency> 
    <dependentassembly> 
    <assemblyidentity type="win32" name="acme.thedll" version="1.2.3.4" processorArchitecture="x86" language="*"/> 
    </dependentassembly> 
</dependency> 

這應該關閉圈應用程序清單(app1.exe.manifest或作爲RT_MANIFEST資源嵌入)並瞭解「acme.thedll」程序集。它還將加載應用程序配置文件(app1.exe.config)並瞭解搜索程序集的私有路徑。然後它會加載並添加「acme.thedll.manifest」到應用程序「激活上下文」。然後,當加載器嘗試加載「thedll.dll」時,它將搜索激活上下文db,在acme.thedll程序集中找到它,並從程序集位置加載它。

+0

感謝您的評論。 我覺得我在我先前的職位回答說,運行時間DLL鏈接是不是我要尋找一個解決方案。並行assmebly概念是好的,但這需要將我們的自定義DLL放入WinSXS目錄並要求管理員權限。有沒有辦法在本地安裝中維護私人商店,並要求我的所有產品應用程序在商店中使用它?有沒有一種方法可以指定在清單文件中以這種方式使用的目錄? -Kartlee – Kartlee 2009-12-29 10:50:18

+0

遺憾的是沒有。私人並排安裝程序在* exe文件夾中只*搜索。我試圖把一個相對路徑放到程序集清單的文件節點的dll中,但是卻無法加載。 Windows配置文件不支持.NET風格配置文件的探測元素。 – 2009-12-29 17:23:04

+0

其實,只要你選擇的操作系統是Windows 7或Sever 2008,你就可以。請參閱我答覆中的受歡迎部分。 – 2009-12-30 20:06:04

0

這可能不會幫助你,但是......你可以加載任意目錄的DLL和仍然依賴於正常的動態鏈接到他們,只要你能控制時,DLL是通過動態鏈接裝載,並確保你已經在動態加載之前已經使用完整路徑顯式加載了dll。

這只是可能會有所幫助,如果你正在寫在您的插件動態鏈接到您希望保持在一個非標準目錄中的DLL插件系統。如果你知道所有關於它們鏈接到的dll的信息,則可以在加載依賴它們的動態dll(插件)之前,直接使用它們的完整路徑直接加載這些dll。由於當您的插件需要找到它時,dll已經在內存中,因此它將使用內存中的版本。您可以卸載加載插件之前所做的顯式加載,並且您可以輕鬆前往。

不幸的是這不會工作,如果你的主要的exe需要加載不受任意地方的dll,你不能得到在今後正常的DLL加載過程。

1

我下面克里斯的回答。確保清單和配置中的案例正確。否則他們會失敗。 我能夠獲得程序集加載,但不會選擇DLL。在我的情況下,系統32中的Windows DLL被選中,而不是我自己的同名。在Dependency Walker中,我的DLL被加載,但在運行時,使用Process Explorer,Windows的副本被加載。有任何想法嗎?