从中央存储库加载DLL的一种方法

我们有很多产品,每个产品的应用程序中都有一些常见的DLL。 现在,我们将每个常见的DLL复制到每个产品的bin目录中,并将它们视为专用程序集。 这不必要地增加了每个产品的msi大小,当DLL发生问题时,我们必须构build包含DLL的每个产品的msi并进行部署。

是否有任何指示产品应用程序使用通用的私人目录来加载DLL [使用清单scheme..]? [注意:将私有目录添加到PATH env将不会提供解决scheme,就好像在SYSTEM目录中存在一个具有相同名称的DLL一样,这将会占用我们专用目录的权限]

-Kartlee

Solutions Collecting From Web of "从中央存储库加载DLL的一种方法"

您不指定您的环境是.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文章“创建并行程序集指南”中进行了介绍


在Windows 6.1及更高版本(Windows server 2008和具有讽刺意味的Windows 7)应用程序配置文件DO Now支持应用程序配置文件中的探测元素

这意味着你应该能够提供一个路径(相对于你的应用程序)到一个包含你想要加载的dll程序集的文件夹。


好吧,我已经做了一些在Windows 7上的测试,这个工程:

假设你有一个应用程序app1.exe安装在\ Program Files \ App1,这取决于一些常见的DLL“thedll.dll”

在应用程序文件夹(\ Program Files \ App1)中创建一个文件App1.exe.config并为其提供以下内容: –

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

现在,创建一个名为\ Program Files \ AcmeCommon的文件夹,并在其中创建一个文件夹acme.thedll,并将该dll.dll复制到\​​ Program Files \ AcmeCommon \ acme.thedll

在AcmeCommon \ acme.thedll中创建一个名为acme.thedll.manifest的文件 – 这将是描述名为“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='*'\"") 

如果您正在使用手动制作清单的较旧版本环境,则需要将以下xml与App1文件夹中的app1.exe.manifest合并:

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

这应该关闭这个循环:当应用程序加载时,win32加载器将加载应用程序清单(app1.exe.manifest或嵌入为RT_MANIFEST资源),并了解“acme.thedll”程序集。 它还将加载应用程序配置文件(app1.exe.config),并了解搜索程序集的私有路径。 然后它会加载并添加“acme.thedll.manifest”到应用程序“激活上下文”。 然后,当加载器尝试加载“thedll.dll”时,它将搜索激活上下文db,在acme.thedll程序集中找到它,并从程序集位置加载它。

如果你在谈论.NET,你可以:

  • 通过使用Assembly.Load(byte[])直接从数据库加载您的DLL
  • 通过使用Assembly.TypeResolve事件
  • 通过使用TypeProvider
  • 通过在配置文件中定义一个探测目录

喜欢:

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

我正在跟随克里斯的回答。 确保清单和配置的情况是正确的。 否则他们会失败。 我能够得到程序集加载,但DLL不会被选中。 在我的情况下,系统32中的Windows DLL被选中,而不是我自己的同名。 在Dependency Walker中,我的DLL被加载,但在运行时,使用Process Explorer,Windows的副本被加载。 有任何想法吗?

我不确定这是你在找什么,但是现在我在哪里工作,我们使用一个通用的UNC路径来处理所有的DLL。

我们有类似…

\\ server01 \ productionLibrary用于生产读取DLL,每个都在它自己的目录中。

\\ server01 \ developmentLibrary,它反映了生产库,这是开发人员在开发时使用的。

当测试完成后我们合并代码,我们将部署到生产库。 所有项目在生成MSI文件进行部署时都会引用生产库。 我们的自动化系统将项目构建到MSI中,并验证所有DLL都指向生产库,因此不可能意外地使用开发副本。

希望这可以帮助。

我不确定我是否正确地理解了这个问题,但是如果您使用.Net,则有一个全局程序集缓存(GAC): http : //en.wikipedia.org/wiki/Global_Assembly_Cache

这缓存了程序集并允许应用程序重用它们(比如.net框架)。 您只需在安装时将程序集注册到GAC,例如提供所有常见程序集的“您的框架安装”,并且只能部署一次。

这可能不会帮助你,但是…你可以从任意目录加载DLL,仍然依靠正常的动态链接到他们,只要你可以控制DLL通过动态链接加载,并确保你已经加载DLL在动态加载之前显式使用完整路径。

如果你正在编写一个插件系统,你的插件被动态地链接到你希望保存在非标准目录下的dll,这可能只会有所帮助。 如果你知道所有关于它们链接到的DLL,你可以在加载依赖它们的动态DLL(插件)之前,直接使用它们的完整路径直接加载这些DLL。 由于当你的插件需要找到它时,dll已经在内存中了,所以它会使用内存中的版本。 您可以卸载加载插件之前所做的显式加载,并且您可以轻松完成。

不幸的是,这不会工作,如果你的主要exe需要从任意地方加载dll,因为你不能在正常的dll加载过程之前。