21

我有从本机 (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 文件夹,以便始终解决依赖关系?或者,这种情况有不同的方法吗?

4

6 回答 6

32

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

于 2010-10-05T14:06:22.127 回答
18

您可以将本机 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,这意味着“如果较新则复制”。

于 2015-10-30T13:15:50.310 回答
6

找到了更好的方法。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>
于 2015-10-01T07:36:20.383 回答
1

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

于 2010-10-05T12:10:06.527 回答
1

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

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

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

编辑不幸的是,这不会影响 DllImport 加载的非托管 DLL

于 2010-10-05T12:13:53.023 回答
0

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

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

只需确保您为所需的每个定位平台都有一个文件夹,例如:lib_x86lib_x64也许lib_AnyCPU

于 2018-10-02T10:07:01.083 回答