有没有更好的方法将本地dll复制到bin文件夹中?

22
我有一个C#包装器代码,调用来自本地(C ++)dll的函数。目前,我可以添加对C# dll的引用,并将“Copy Local”选项设置为true。但是,作为依赖项的本地dll无法作为引用添加,因此没有“Copy Local”选项。
我尝试了以下方法:
1. 使用后构建事件将本地dll从Libs文件夹复制到$(TargetFolder) copy "$(ProjectDir)Libs\NQuantLibc.dll" "$(TargetDir)NQuantLibc.dll" 2. 将本地dll作为现有项目项包含在项目中(添加->现有项->包含dll)。此选项允许我使用“Copy Local”选项。采用这种方法的缺点是dll始终显示为项目项。
我还尝试了“显示所有文件”,这使我可以看到Libs文件夹。然后,我在项目中包含了NQuantLibc.dll文件,这使我可以设置'Copy Local'选项。然而,这给了我一个意外的结果。它在bin文件夹中创建了一个包含dll的Libs子文件夹(例如bin/debug/Libs/NQuantLibc.dll)。这不理想,因为C# dll不能正确调用本地dll,因为它不存在。
以上两种方法都有效。是否有更好的方法将本地dll复制到bin文件夹中,以便始终解决依赖项?或者,是否有一种不同的方法来处理这种类型的情况?

相关问题:https://dev59.com/GUXRa4cB1Zd3GeqPqUm4 - Ahmad
6个回答

33

使用 Project + Add Existing Item,选择 DLL 文件。在解决方案资源管理器窗口中选择添加的文件。在“属性”窗口中,将“复制到输出目录”设置更改为“如果较新则复制”。


1
不,它没有。请注意我的建议:“如果较新则复制”。 - Hans Passant
@hans - 哈哈,我的留在办公室了。但说真的,如果我做错了什么,我会很感激你能给我澄清,这样我就可以从错误中学习。 - Ahmad
4
@Ahmad:在对话框中添加现有项时,请注意“添加”按钮的下拉部分,并将其更改为“添加为链接”。这在用户界面中很容易被忽略。 - nitrogenycs
1
非常小心使用“添加为链接”。一年后,这可能不再起作用。或者说,在另一台机器上,今天也是如此。很容易忘记将DLL签入源代码控制。 - Hans Passant
如果您不选择“添加为链接”,则需要确保您在项目中使用与磁盘上相同的文件夹结构添加dll。否则,VS将创建另一个dll副本。对于这种情况,我的假设是dll已经被检入到源代码控制的中央位置,以供多个项目共享。在这种情况下,您不希望VS在每个项目中创建另一个副本。添加为链接可以让您更新集中式dll而不触及引用它的所有项目。 - Tim Sparkles
显示剩余6条评论

21

您可以将本地dll作为链接项添加,并使用"仅在较新时复制"选项。
本地dll的问题在于,有时根据项目的配置(调试/发布或平台)需要使用不同的dll。

您可以编辑项目的.csproj文件并有条件地链接本地dll:

 <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|Win32' ">
    <Content Include="..\..\bin\Win32\Release\NQuantLibc.dll">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
 </ItemGroup>   
 <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|Win32' ">
    <Content Include="..\..\bin\Win32\Debug\NQuantLibc_d.dll">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
  <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
    <Content Include="..\..\bin\x64\Debug\NQuantLibc_d.dll">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
  <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
    <Content Include="..\..\bin\x64\Release\NQuantLibc.dll">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

请注意,复制选项已设置为 PreserveNewest,意思是“仅在新的情况下进行复制”。


4
令人惊奇的是,曾经是主流开发模式的东西现在变得如此奇怪,以至于你必须手动编辑一个 .csproj 文件。 - zumalifeguard

6

找到了更好的方法。Nuget可以添加.targets文件,这些文件存储在包的构建文件夹中,可以将其添加到您的项目中。通过这种方式,您可以在每次构建时将包中的某些文件复制到任何位置。在下面的示例中,我将一些非DotNet DLL存储在“binaries”文件夹中。每次构建时,它会检查DLL是否已经复制到输出文件夹($OutputPath变量)中,并在必要时复制它们。

Nuspec内容:

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
    <metadata>
        <id>Example</id>
        <version>1.0.0</version>
        <authors>Example</authors>
        <requireLicenseAcceptance>false</requireLicenseAcceptance>
        <description>Example</description>
    </metadata>
    <files>
        <file src="Non-DotNet.dll" target="binaries\Non-DotNet.dll" />
        <file src="DotNet.dll" target="lib\net40\DotNet.dll" />
        <file src="Example.targets" target="build\Example.targets" />
    </files>
</package>

例子.targets 内容:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Target Name="CopyBinaries" BeforeTargets="BeforeBuild">
        <CreateItem Include="$(MSBuildThisFileDirectory)..\binaries\**\*.*">
            <Output TaskParameter="Include" ItemName="PackageBinaries" /> 
        </CreateItem>

        <Copy SourceFiles="@(PackageBinaries)"
              DestinationFolder="$(OutputPath)"
              SkipUnchangedFiles="true"
              OverwriteReadOnlyFiles="true"
        />
    </Target>
</Project>

1

如果您对创建的“Libs”文件夹满意,可以尝试将其添加到应用程序的探测路径中,方法是在app.config文件中添加以下内容:

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

这将导致运行时在所有指定的目录中查找DLL。 编辑 不幸的是,这不会影响DllImport加载非托管DLL

我在 Stack Overflow 上很忙,试图找出为什么会抛出异常 :(。还是谢谢。 - Ahmad

1
将dll作为项目中的文件添加(如果您仍希望它驻留在另一个目录中,则可能需要选择“作为链接”)。然后将构建操作设置为内容,将复制到输出目录设置为true。

这适用于VS 2010 Express吗?我似乎找不到“添加链接”选项。其余的答案似乎与第2点描述的非常相似。我错了吗? - Ahmad
@Ahmad,您可以通过按下“添加”按钮上的小向下箭头(从添加→现有项目...),并选择“添加为链接”,将文件作为链接添加。 - Igal Tabachnik
@hmemcpy - 看起来不起作用。Dll 没有被复制到 bin 文件夹中,导致对应的异常被抛出。 - Ahmad
实际上它正在被复制,但是到一个名为Libs的子文件夹中。 - Ahmad

0

显然我遇到了相同的问题,但是我不想进行项目文件编辑,所以最终我使用以下后构建脚本:

xcopy /y "$(ProjectDir)\lib_$(Platform)\*.dll" "$(ProjectDir)$(OutDir)"

只需要确保为每个需要的目标平台都有一个文件夹,例如:lib_x86lib_x64,甚至可能是 lib_AnyCPU


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接