Есть ли лучшие способы скопировать нативный dll в папку bin? - PullRequest
14 голосов
/ 05 октября 2010

У меня есть код оболочки C #, который вызывает функции из нативной (C ++) dll.В настоящее время я могу добавить ссылку на C # dll и установить для параметра «Копировать локальный» значение true.Однако нативная библиотека DLL, которая является зависимостью, не может быть добавлена ​​в качестве ссылки - поэтому нет опции «Копировать локально».

Я пробовал следующие подходы

  1. Использование событий после сборки для копирования собственной библиотеки DLL из папки Libs в $(TargetFolder)

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

  2. Включение встроенной библиотеки DLL в качестве существующего элементав проекте (Добавить -> Существующий элемент -> Включить DLL).Эта опция позволяет мне использовать опцию «Копировать локально».Недостатком этого подхода является то, что dll всегда отображается как элемент проекта.

Я также попробовал «Показать все файлы», что позволило мне увидеть папку Libs.Затем я включил в проект файл NQuantLibc.dll, который позволил мне установить опцию «Копировать локально».Однако это дало мне неожиданный результат.Он создал подпапку Libs, содержащую dll в папке bin (например, bin/debug/Libs/NQuantLibc.dll).Не идеально, так как C # dll не смог правильно вызвать нативный dll, поскольку его там не было.

Обе вышеуказанные опции работают.Есть ли лучшие способы скопировать нативный dll в папку bin, чтобы зависимость всегда была разрешена?В качестве альтернативы, есть ли другой подход к сценарию такого типа?

Ответы [ 6 ]

25 голосов
/ 05 октября 2010

Используйте Project + Add Existing Item и выберите DLL. Выберите добавленный файл в окне обозревателя решений. В окне «Свойства» установите для параметра «Копировать в каталог вывода» значение «Копировать, если новее».

14 голосов
/ 30 октября 2015

Вы можете добавить нативную 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 , что означает «копировать, если новее».

5 голосов
/ 01 октября 2015

Нашли лучший способ.Nuget может добавлять файлы .targets, которые хранятся в папке сборки пакета, в ваш проект.Таким образом, вы можете копировать в каждую сборку некоторые файлы из вашего пакета, где вы хотите.В следующем примере я сохранил некоторые библиотеки 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 content:

<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 голос
/ 05 октября 2010

Если вы в порядке с созданной папкой "Libs", вы можете попробовать добавить ее в пробный путь для вашего приложения, добавив в файл app.config следующее:

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

Это заставит среду выполнения искать во всех указанных каталогах DLL.

EDIT К сожалению, это не влияет на неуправляемую загрузку DLL с помощью DllImport .

1 голос
/ 05 октября 2010

Добавьте dll в виде файла в проект (возможно, «как ссылка», если вы все еще хотите, чтобы он находился в другом каталоге). Затем установите для параметра Build Action значение content и значение Copy to output directory для true.

0 голосов
/ 02 октября 2018

Очевидно, у меня возникла та же проблема, но я не хотел так сильно редактировать файл проекта, поэтому я использовал следующий сценарий после сборки:

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

Просто убедитесь, что у вас есть папка для каждой целевой платформы, например: lib_x86, lib_x64 и, возможно, lib_AnyCPU

...