WPF: 把引用的dll移动到自定义路径

来源:互联网 发布:javascript与jsp 编辑:程序博客网 时间:2024/05/01 17:17

需求:

有A.exe和B.exe, 都引用了 C.dll, output路径都是 W:\Debug. 
A和B都添加了对C的引用,正常情况下C会被复制到 output 里面。 
C这样子的dll很多,不想把它们和exe放在同一级的目录,移动到子目录,如W:\Debug\3rdDll

 

办法:

1. 首先设置C.dll 

打开Project A的References,选中C.dll, 右键Properties,Copy Local 设为False,这个dll就不会拷贝了。

2. 设置PostBuild,

打开B的Build Events,  PostBuild 输入

mkdir  $(OutputPath)\3rdDll 
move $(OutputPath)\c.dll  $(OutputPath)\3rdDll\c.dll

A和B可以互换。

3. A和B 加入Config文件,

Config:  Build Action=None, Copy to Output Directory=Do not copy

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
  <runtime> 
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
      <probing privatePath="3rdDll;"/> 
    </assemblyBinding> 
  </runtime> 
</configuration>


类似于:

<configuration>

    <runtime>

        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

            <dependentAssembly>

                <!-- 不是强命名程序集,不用设置version,publicKeyToken…… -->

                <assemblyIdentity name="ClassLibrary1"/>

                <!-- 不是强命名程序集,不用设置version, 设置href指定文件位置 -->

                <codeBase href="file:///E:/Visual Studio 2010/Projects/Mgen/bin/Debug/dlls/ClassLibrary1.dll" />

            </dependentAssembly>

        </assemblyBinding>

    </runtime>

</configuration>



或者 app.xaml.cs里面加入:

public App() 
       { 
           this.Startup += new StartupEventHandler(App_Startup); 
       }

       void App_Startup(object sender, StartupEventArgs e) 
       { 
           var name = Assembly.GetExecutingAssembly().Location; 
           var path = Path.GetDirectoryName(name); 
           AppDomain.CurrentDomain.AppendPrivatePath(path+ @"\3rdDll"); 
       }

 

AppDomain.CurrentDomain.AppendPrivatePath 貌似过时了,AppDomainSetup 的使用方法没找到。

注意:3rdDll这个文件夹必须在 W:\Debug 的子目录或者更深一级的目录。

 

特殊需求:

F.dll 不在 W:\Debug 的子目录或者更深一级的目录,例如上一级目录;

或者exe的目录级别比dll的低一些,

用这个办法:

public App() 
       { 
           AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); 
       }

       System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
       { 
           var name = Assembly.GetExecutingAssembly().Location; 
           var path = Path.GetDirectoryName(Path.GetDirectoryName(name)); 
           var dllPath = path + @"\3rdDll\F.dll"; 
           return Assembly.LoadFrom(dllPath); 
       }


其它:

  要从程序集的元数据中获取程序集的信息,首先需要加载程序集。.Net中加载程序集方法有几种,本人结合自己的实践和认识简单介绍一下。描述不一定很准确,请提出来一起进步。

一、隐式加载
        没有被显式加载但被引用的程序集,CLR会按照全局程序集缓存(GAC)、工作目录(应用程序所在目录)以及私有路径目录的顺序来寻找并加载。

二、AppDomain.Load 方法
    将一个程序集加载到一个特定的程序域中,主要用来供非托管代码调用

三、Assembly.Load方法
    通过接受一个程序集标识来加载程序集。如果是强命名程序集,则标识包括程序集名称、版本、语言文化、以及公有密钥标记,Load方法将导致CLR按照隐式加载的策略寻找并加载程序集。弱命名程序集则只是一个不带文件扩展名的程序集的名称,CLR不会到GAC中查找,如果没有指定私有目录,则在工作目录查找,如Assembly.Load("Math")。其中私有目录的定义可以在配置文件中指定。如应用程序MyApp.exe的配置文件可以定义为MyApp.exe.config。内容:
    

  1.  <?xml version="1.0" encoding="utf-8" ?>
  2.     <configuration>
  3.        <runtime>
  4.           <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
  5.              <probing privatePath="App;App1;" />
  6.           </assemblyBinding>
  7.        </runtime>
  8.     </configuration>

  

     其中App和App1是两个在工作目录下的目录,用probing定义,存放需要在这个目录下被加载的程序集。如果使用工作目录以外的目录下的程序集,则可以使用codeBase元素来定义,可以在MSDN上查找其属性内容。

四、Assembly.LoadFrom方法
    参数是包括程序集清单的文件的名称或路径,包括文件扩展名。如需要加载D:/App/math.dll,可以使用语句:
    Assembly a = Assembly.LoadFrom(@"D:/App/math.dll");
    a即是加载的程序集。
    但这种方法有缺点,在MSDN上有详细的描述,我自己遇到的一个问题是加载一个在非工作目录下的程序集后,在另一个程序集中使用这个程序集中的对象进行反序列化时失败。使用Assembly.Load方法或者将该程序集放在工作目录下后问题得以解决。

五、Assembly.LoadFile方法
    用来加载指定路径上的程序集文件的内容。使用 LoadFile 方法来加载和检查具有相同标识但位于不同路径中的程序集。与 LoadFrom 不同,LoadFile 不会将文件加载到 LoadFrom 上下文中,也不会使用加载路径解析依赖项。LoadFile 在这个受限制的方案中很有用,因为 LoadFrom 不能用于加载标识相同但路径不同的程序集;它只加载第一个这样的程序集。

六、Assembly.LoadWithPartialName方法
    使用部分名称从应用程序目录或从全局程序集缓存加载程序集。参数为程序集标识,其中包含程序集的名称(不带文件扩展名)。程序集的版本、语言文化及公用密钥标记为可选。该方法执行时CLR首先检查应用程序的XML配置文件来搜索qualifyAssembly元素,若存在则该元素应能告诉CLR如何将一个部分的程序集标识映射为完全限定的标识,CRL将根据通常规则来查找程序集。若该元素不存在,CRL将使用指定名称在应用程序的工作目录和私有路径目录中搜索。若仍未找到,则到GAC中查找。

七、传统VC动态库的调用
    通过 P/Invoke 调用Win32 DLL

    using System.Runtime.InteropServices;//这是用到DllImport时候要引入的程序集

    [DllImport("DBAccess.dll",CharSet=CharSet.Auto)]
    static extern ulong FindApp( bool bIsTrue );
    //声明外部的标准动态库,跟Win32API是一样的.



Over!

0 0
原创粉丝点击