Скопируйте собственные зависимости локально в проекте Visual Studio

У меня есть проект С++ смешанного режима, создающий сборку управляемых dll, экспортирующих некоторые классы CLR (назовите это Managed.dll). Этот проект использует родную dll (назовите его Native.dll).

Когда я ссылаюсь на Managed.dll из другого проекта, создающего Client.exe, все работает так, как ожидалось, за исключением того, что мне нужно вручную скопировать файл Native.dll в ту же папку, что и Client.exe.

Если есть способ убедить VS скопировать локально (в папку bin из Client.exe) не только Managed.dll, но и Native.dll?

Я попытался включить Native.dll в сборку зависимостей в манифесте, но это не помогло.

Edit

Managed.dll будет распространяться на сборку. Он будет установлен в папке "C:\Program Files.....". Когда разработчик, использующий Visual Studio, добавляет ссылку на Managed.dll, Native.dll следует также скопировать в папку \bin его проекта.

Ответ 1

Существует несколько способов сообщить VS скопировать dll в папку назначения:

1. Добавьте DLL в качестве ресурса проекта. И скажите VS, чтобы скопировать его, если dll более новая

2. Добавьте новый проект, ссылающийся на проект dll, и установите OutDir в нужную папку. Этот проект ничего не делает, кроме как скопировать dll.

3.Используйте PostBuildEvent в файле vcxproj.

<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
  <ClCompile>
  </ClCompile>
  <Link>
  </Link>
  <PostBuildEvent>
    <Command>
      echo off
      mkdir "$(ProjectDir)..\..\bin\$(Configuration)\"
      copy "$(OutDir)xxx.dll" "$(ProjectDir)..\..\lib\$(Configuration)\"
      echo on
    </Command>
  </PostBuildEvent>
</ItemDefinitionGroup>

4.Используйте PreBuildEvent в файле vcxproj.

5.Используйте CustomBuild в файле vcxproj

<ItemGroup>
<CustomBuild Include="..\..\xxx.dll">
  <FileType>Document</FileType>
  <Command>
   call mkdir &quot;$(OutDir)&quot; 2&gt;nul &amp; 
   copy /Y &quot;..\..\xxx.dll&quot; &quot;$(OutDir)xxx.dll&quot;
  </Command>
  <Message>Copying xxx.dll to $(OutDir)\xxx.dll</Message>
  <Outputs>$(OutDir)\xxx.dll</Outputs>
</CustomBuild>
</ItemGroup>

6.Используйте make файл и скопируйте dll в make файл. и используйте nmake для сборки

7. Запишите файл bat, который выполняет задание на копирование, и вызовите файл bat как в 3-6

8.Use script, например python, который также может загрузить DLL из Интернета. И вызовите файл py как в 3-6.

9. Другие инструменты сборки также могут помочь, например gradle

10. Внесите его в плагин NuGet

11. Иногда я просто пишу летучую мышь и выполняю летучую мышь вручную.

Обновление 01 (пример самопривлекательной dll):

1.Добавьте свою родную DLL как ресурс управляемой dll

2. Добавьте этот метод init()

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace DllSelfExtract
{
    public class SelfExtract
    {
        public static void Init()
        {
            String managedDllPath = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
            String nativeDllPath = managedDllPath.Replace("file:///", "").Replace("DllSelfExtract.DLL", "TestDll.dll");
            if(!File.Exists(nativeDllPath))
            {
                Stream dllIn = Assembly.GetExecutingAssembly().GetManifestResourceStream("DllSelfExtract.TestDll.dll");
                if (dllIn == null) return;

                using (Stream outFile = File.Create(nativeDllPath))
                {
                    const int sz = 4096;
                    byte[] buf = new byte[sz];
                    while (true)
                    {
                        int nRead = dllIn.Read(buf, 0, sz);
                        if (nRead < 1)
                            break;
                        outFile.Write(buf, 0, nRead);
                    }
                }
            }

            //LoadLibrary Here
        }
    }
}

3. В проекте, использующем вашу управляемую DLL, сначала вызовите метод init()

SelfExtract.Init();

Обновление 02 (пример NuGet):

1.Создайте новый проект NuGet

2. Установите управляемые сборки в каталоге /lib

3. Поместите не управляемые совместно используемые библиотеки и связанные файлы в подкаталог /build и переименуйте все не управляемые *.dll в *.dl _

4. Добавьте собственный файл .targets в подкаталог /build с чем-то вроде следующего содержимого:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <AvailableItemName Include="NativeBinary" />
  </ItemGroup>
  <ItemGroup>
    <NativeBinary Include="$(MSBuildThisFileDirectory)*">
      <TargetPath></TargetPath>
    </NativeBinary>
  </ItemGroup>
  <PropertyGroup>
    <PrepareForRunDependsOn>
      $(PrepareForRunDependsOn);
      CopyNativeBinaries
    </PrepareForRunDependsOn>
  </PropertyGroup>
  <Target Name="CopyNativeBinaries" DependsOnTargets="CopyFilesToOutputDirectory">
    <Copy SourceFiles="@(NativeBinary)"
          DestinationFiles="@(NativeBinary->'$(OutDir)\%(TargetPath)\%(Filename).dll')"
          Condition="'%(Extension)'=='.dl_'">
      <Output TaskParameter="DestinationFiles" ItemName="FileWrites" />
    </Copy>
    <Copy SourceFiles="@(NativeBinary)"
          DestinationFiles="@(NativeBinary->'$(OutDir)\%(TargetPath)\%(Filename).%(Extension)')"
          Condition="'%(Extension)'!='.dl_'">
      <Output TaskParameter="DestinationFiles" ItemName="FileWrites" />
    </Copy>
  </Target>
</Project>

5.Добавить правило сборки для папки сборки в Package.nuspec

<files>
  <file src="lib\" target="lib" />
  <file src="tools\" target="tools" />
  <file src="content\" target="content" />
  <file src="build\" target="build" />
</files>

6.Построить пакет

7. В другом проекте С# просто добавьте этот пакет NuGet.

Ответ 2

Использование опции /ASSEMBLYLINKRESOURCE в свойствах компоновщика представляется самым простым решением. Это заставляет Visual Studio рассматривать родную dll как часть сборки. Кроме того, в соответствии с документацией, предоставленной Microsoft, разрешено устанавливать встроенную DLL в глобальный кэш сборок

Чтобы установить этот вариант компоновщика в проекте Visual С++:

  • Щелкните правой кнопкой мыши имя проекта и выберите Свойства
  • Выберите папку Linker
  • На странице свойств Вход найдите параметр Ресурс компоновки ссылок
  • Введите имя файла собственной сборки, например. MyNative.dll

Вам понадобится событие Post Build, чтобы скопировать родную DLL в выходную папку.

Ссылка на управляемую сборку из любого другого Visual Project заставляет скопировать собственную DLL вместе с управляемой сборкой в ​​папке/bin.