在Visual Studio项目中本地复制本机依赖项

时间:2016-09-02 14:56:06

标签: c++ .net visual-studio

我有一个混合模式C ++项目,它生成一个托管dll程序集,导出一些CLR类(称之为Managed.dll)。这个项目使用的是本机dll(称之为Native.dll)。

当我从另一个生成Client.exe的项目引用Managed.dll时,一切都按预期工作,除了我需要手动将Native.dll复制到与Client.exe相同的文件夹中。

如果有办法说服VS本地复制(在Client.exe的bin文件夹中)不仅Managed.dll而且还有Native.dll?

我试图在清单中包含Native.dll作为依赖程序集,但这没有帮助。

修改

Managed.dll将成为可再发行组件。它将安装在“C:\ Program Files .....”的文件夹中。当使用Visual Studio的开发人员添加对Managed.dll的引用时,还应将Native.dll复制到其项目的\ bin文件夹中。

2 个答案:

答案 0 :(得分:11)

有几种方法可以告诉VS将dll复制到目标文件夹:

1.添加dll作为项目的资源。如果dll更新,请告诉VS复制

2.添加一个引用dll项目的新项目,并将OutDir设置为所需的文件夹。该项目除了复制dll外什么都不做。

3.在vcxproj文件中使用PostBuildEvent

<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.在vcxproj文件中使用PreBuildEvent

5.在vcxproj文件中使用CustomBuild

<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.使用makefile并在makefile中复制dll。并使用nmake构建

7.编写执行复制作业的bat文件,并按照3-6

调用bat文件

8.使用python这样的脚本,也可以从互联网上下载dll。并按照3-6中的方式调用py文件。

9.其他构建工具也可以提供帮助,例如gradle

10.使其成为NuGet插件

11.有时我只是写一个蝙蝠,然后手动执行蝙蝠。

更新01(Self extract 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.在/ build子目录中添加一个自定义.targets文件,其中包含以下内容:

<?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.在你的另一个C#项目中,只需添加这个NuGet包。

答案 1 :(得分:7)

在链接器属性中使用/ASSEMBLYLINKRESOURCE选项似乎是最简单的解决方案。它使Visual Studio将本机dll视为程序集的一部分。此外,根据Microsoft提供的文档,允许本机dll安装在全局程序集缓存

在Visual C ++项目中设置此链接器选项:

  • 右键单击项目名称,然后选择属性
  • 选择链接器文件夹
  • 输入属性页中,找到程序集链接资源选项
  • 写出本机程序集的文件名,例如的 MyNative.dll

您需要Post Build事件才能将本机dll复制到输出文件夹。

从任何其他Visual Project引用托管程序集,强制将本机dll与/ bin文件夹中的托管程序集一起复制。