我有一个混合模式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文件夹中。
答案 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 "$(OutDir)" 2>nul &
copy /Y "..\..\xxx.dll" "$(OutDir)xxx.dll"
</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 ++项目中设置此链接器选项:
您需要Post Build事件才能将本机dll复制到输出文件夹。
从任何其他Visual Project引用托管程序集,强制将本机dll与/ bin文件夹中的托管程序集一起复制。