【问题标题】:Are there any better ways to copy a native dll to the bin folder?有没有更好的方法将本机 dll 复制到 bin 文件夹?
【发布时间】:2010-10-05 12:03:43
【问题描述】:

我有从本机 (C++) dll 调用函数的 C# 包装器代码。目前,我可以添加对 C# dll 的引用并将“复制本地”选项设置为 true。但是,作为依赖项的本机 dll 不能作为参考添加 - 因此没有“复制本地”选项。

我尝试了以下方法

  1. 使用构建后事件将本地 dll 从 Libs 文件夹复制到 $(TargetFolder)

    copy "$(ProjectDir)Libs\NQuantLibc.dll" "$(TargetDir)NQuantLibc.dll"

  2. 将本机 dll 作为现有项目包含在项目中(添加 -> 现有项目 -> 包含 dll)。此选项允许我使用“复制本地”选项。这种方法的缺点是 dll 总是显示为项目项。

我还尝试了“显示所有文件”,这让我可以看到 Libs 文件夹。然后我在项目中包含 NQuantLibc.dll 文件,它允许我设置“复制本地”选项。然而,这给了我一个意想不到的结果。它在bin 文件夹中创建了一个包含dll 的Libs 子文件夹(例如bin/debug/Libs/NQuantLibc.dll)。不理想,因为 C# dll 不存在,因此无法正确调用本机 dll。

以上两个选项都有效。有没有更好的方法将本机 dll 复制到 bin 文件夹,以便始终解决依赖关系?或者,这种情况有不同的方法吗?

【问题讨论】:

标签: .net visual-studio build post-build-event


【解决方案1】:

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

【讨论】:

  • 我不明白这个问题,它一个项目项。没有它就不会运行,就像缺少源代码文件时它不会运行一样。
  • @hans - 我不是说有问题。我只是在寻找更好的方法。我认为有一个问题值得关注。将 DLL 添加为现有项时,会在您的项目文件夹中创建 DLL 的副本,因此如果您的原始 DLL 得到更新,您将需要将其重新添加到项目中。在这种情况下,构建后复制命令将更加强大 IMO。
  • 不,它没有。注意我的建议:“如果更新就复制”。
  • @Ahmad:在对话框中添加现有项目时,请注意“添加”按钮的下拉部分,并将其更改为“添加为链接”。这在 UI 中很容易被忽略。
  • 非常小心“添加为链接”。一年后,这可能不再有效。或者今天在另一台机器上。太容易忘记将 DLL 签入到源代码管理中。
【解决方案2】:

您可以将本机 dll 添加为链接项,并使用“Copy if newer”。
原生 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,这意味着“如果较新则复制”。

【讨论】:

  • 令人惊讶的是,过去的主线开发模式现在变得如此古怪,以至于您必须手动编辑 .csproj 文件。
【解决方案3】:

找到了更好的方法。 Nuget 可以将存储在包的 build 文件夹中的 .targets 文件添加到您的项目中。通过这种方式,您可以在每次构建时复制包的一些文件,无论您想要什么。在以下示例中,我将一些非 DotNet DLL 存储到“二进制”文件夹中。在每次构建时,它会检查 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>

Example.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>

【讨论】:

    【解决方案4】:

    将 dll 作为文件添加到项目中(如果您仍希望它驻留在另一个目录中,则可能是“作为链接”)。然后将 Build Action 设置为 content 并将 Copy to output directory 设置为 true。

    【讨论】:

    • 这是否适用于 VS 2010 Express?我似乎找不到“添加链接”选项。其余的答案似乎与第 2 点中描述的非常相似。我弄错了吗?
    • @Ahmad 您可以通过按“添加”按钮上的小向下箭头(从添加 → 现有项目...)并选择 Add as Link 将文件添加为链接
    • @hmemcpy - 似乎不起作用。 Dll 没有被复制到 bin 文件夹中,并且正在引发相应的异常。
    • 实际上是被复制到了一个 Libs 子文件夹中
    【解决方案5】:

    如果您对创建的“Libs”文件夹没有问题,您可以尝试将其添加到您的应用程序的 probing path,方法是在 app.config 文件中添加以下内容:

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

    这将导致运行时在所有指定的目录中查找 DLL。

    编辑不幸的是,这个does not impact the unmanaged DLL loading by DllImport

    【讨论】:

    • 我正忙着试图找出抛出异常的原因:(。不过谢谢。
    【解决方案6】:

    显然我碰巧遇到了同样的问题,但我不想做太多的项目文件编辑,所以我最终使用了以下构建后脚本:

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

    只需确保您为所需的每个定位平台都有一个文件夹,例如:lib_x86lib_x64 甚至可能是lib_AnyCPU

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-10
      • 1970-01-01
      • 1970-01-01
      • 2021-07-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多