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

时间:2010-10-05 12:03:43

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

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

我尝试了以下方法

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

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

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

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

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

6 个答案:

答案 0 :(得分:23)

使用Project + Add Existing Item并选择DLL。在Solution Explorer窗口中选择添加的文件。在“属性”窗口中,将“复制到输出目录”设置更改为“如果更新则复制”。

答案 1 :(得分:14)

您可以将原生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 ,这意味着&#34;如果更新则复制&#34;。

答案 2 :(得分:5)

找到了更好的方法。 Nuget可以将.targets文件,存储在包的build文件夹中,添加到您的项目中。通过这种方式,您可以在每个构建中复制包的任何文件,无论您想要什么。在下面的示例中,我将一些Non 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>

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>

答案 3 :(得分:1)

将dll添加为项目中的文件(如果您仍希望它位于另一个目录中,则为“As link”)。然后将Build Action设置为content,将Copy to output目录设置为true。

答案 4 :(得分:1)

如果您对创建的“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

答案 5 :(得分:0)

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

var jobRefs = context.jobs.Where(j => j.LSM_Status == null && j.despatched_time == null ) .Select(x => new { x.job_ref, x.volumes_env, x.postout_deadline , x.UniqNo }) .ToList(); var UpdatedRefs = context.customerslas.Where(c => jobRefs.Any(z=>z.job_ref == c.job_ref) && (c.invoiced == 1 || c.invoiced == 2) && c.active == 1) .Select(c => c.job_ref) .ToList();

只需确保为每个所需的定位平台都有一个文件夹,例如:xcopy /y "$(ProjectDir)\lib_$(Platform)\*.dll" "$(ProjectDir)$(OutDir)"lib_x86,甚至还有lib_x64