Есть ли лучшие способы копирования родной DLL в папку bin?

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

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

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

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

  • Включена родная dll в качестве существующего элемента в проекте (Добавить → Существующий элемент → Включить dll). Этот параметр позволяет мне использовать параметр "Копировать локальный". Недостатком этого подхода является то, что dll всегда отображается как элемент проекта.

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

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

Ответ 1

Используйте Project + Добавить существующий элемент и выберите DLL. Выберите добавленный файл в окне обозревателя решений. В окне "Свойства" измените параметр "Копировать в каталог вывода" на "Копировать, если новый".

Ответ 2

Вы можете добавить родную dll как связанный элемент и использовать " Копировать, если новый".
Проблема с родными dll заключается в том, что иногда вам нужно использовать разные dll в соответствии с конфигурацией проекта (Debug/Release или platform).

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

Ответ 3

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

Пример. content 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>

Ответ 4

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

Ответ 5

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

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

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

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