如何修改正在使用的dll?

时间:2015-05-27 15:54:36

标签: .net windows multithreading

如果我有多个同一进程的实例访问某个dll,是否有办法让其中一个进程获取锁定,删除它,替换它并继续?

1 个答案:

答案 0 :(得分:3)

为了能够替换正在使用的dll,使用它们的程序必须在" Shadow Copy"模式。这样做不是直接使用文件,而是程序集生成文件的副本并将其复制到内存中。这允许您替换或删除当前运行的应用程序的DLL,当下次重新启动应用程序时,它将获取当前版本的新副本。这就是IIS如何使您可以更新正在使用的网站,它阴影复制其程序集以及当它检测到对目录的更改时,它会重新启动网站加载新版本的程序集。

卷影复制设置为AppDomain level setting,但是一旦启动AppDomain,您就无法更改设置。

启用卷影复制的两种方法是使用小型的#34; Loader"在您的程序之前启动的应用程序域,此加载程序启动一个启用了Shadow Copy的新AppDomain,然后开始组装。

private static void Main(string[] args)
{
    if (AppDomain.CurrentDomain.ShadowCopyFiles == false)
    {

        var assembly = Assembly.GetEntryAssembly();
        var currentAppDomain = AppDomain.CurrentDomain;
        AppDomain newDomain = AppDomain.CreateDomain("ShadowedDomain", 
            null,
            currentAppDomain.BaseDirectory,
            currentAppDomain.RelativeSearchPath, 
            true); //<-- This true is what enables Shadow Copy on the AppDomain.

        //This calls Main again in the new AppDomain and blocks till the call to Main exits.
        newDomain.ExecuteAssembly(assembly.Location, args);
     }
    else
    {
        RealMain(args);
    }
}

private static void RealMain(string[] args)
{
    //Your code here.
}

一个缺点是您的主EXE仍将被锁定,但任何DLL的EXE加载都将使用Shadow Copy加载。

另一个选项与第一个类似,但您可以告诉自己的程序集使用自定义加载程序启用Shadow Copy,而不是手动运行加载程序并将其指向程序集。要做到这一点,首先创建一个单独的dll作为加载器并使其包含一个派生自AppDomainManager的类,此文件不会被复制阴影。

using System;

namespace DomainManager
{
    public class ShadowDomainManager : AppDomainManager
    {
        public override void InitializeNewDomain(AppDomainSetup appDomainInfo)
        {
            base.InitializeNewDomain(appDomainInfo);
            appDomainInfo.ShadowCopyFiles = "true";
        }
    }
}

然后在程序集的app.config中,您可以告诉它使用您的加载程序dll。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
    <runtime>
      <appDomainManagerType value="DomainManager.ShadowDomainManager" />
      <appDomainManagerAssembly
         value="DomainManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </runtime>
</configuration>

现在您的exe及其加载的任何DLL(存储在应用程序目录或其子目录中)将被加载到Shadow Copied App Domain中,并且可以在使用时删除/替换。