我目前正在用C ++和C#编程。使用本机C ++进行数值计算部分。
最初我打算使用C ++ / CLI来创建本机C ++类的包装器,但我发现它会导致2到4倍的减速。
所以我决定将我的原生C ++编译成DLL,并通过P/Invoke调用.NET / C#。我将在C#中进行数据预处理,并在本机DLL中进行数字运算。
问题在于,当我将作品交给他人使用时,我希望它是一个单独的DLL。
这可能吗?顺便说一下,我有原生C ++的所有源代码。
答案 0 :(得分:6)
通过生成netmodules,您可以非常轻松地完成此操作。将组合的C ++和C ++ / CLI代码编译为.obj(C ++ netmodules具有文件扩展名.obj,C#netmodules具有文件扩展名.netmodule),然后将其链接到您的C#项目。
详细信息:http://blogs.msdn.com/junfeng/archive/2005/05/19/420186.aspx。 工作示例:http://blogs.msdn.com/b/junfeng/archive/2006/05/20/599434.aspx。
答案 1 :(得分:2)
我过去使用过的另一个选项是让你的program / dll充当自解压存档。将托管dll作为压缩资源加载,并将其解压缩到您运行的任何计算机的临时文件夹中。
我有一个使用AlphaVSS的应用程序,它内置了一些本机DLL。我希望应用程序作为单个exe完全可移植,不需要安装。以下是我处理它的方式。
public static void ExtractResources()
{
Directory.CreateDirectory(Path.Combine(Program.DataPath, FolderName));
//Extract the runtime in case it is not installed on the destination computer
if (NativeMethods.Is64BitOperatingSystem)
{
FileUtils.DecompressFile(Path.Combine(Program.DataPath, FolderName + @"\Microsoft.VC90.CRT.manifest"),
Resources.x64.X64Resources.Microsoft_VC90_CRT_manifest);
FileUtils.DecompressFile(Path.Combine(Program.DataPath, FolderName + @"\msvcm90.dll"), Resources.x64.X64Resources.msvcm90_dll);
FileUtils.DecompressFile(Path.Combine(Program.DataPath, FolderName + @"\msvcp90.dll"), Resources.x64.X64Resources.msvcp90_dll);
FileUtils.DecompressFile(Path.Combine(Program.DataPath, FolderName + @"\msvcr90.dll"), Resources.x64.X64Resources.msvcr90_dll);
FileUtils.DecompressFile(Path.Combine(Program.DataPath, FolderName + @"\AlphaVSS.52.x64.dll"), Resources.x64.X64Resources.AlphaVSS_52_x64_dll);
FileUtils.DecompressFile(Path.Combine(Program.DataPath, FolderName + @"\AlphaVSS.60.x64.dll"), Resources.x64.X64Resources.AlphaVSS_60_x64_dll);
}
else
{
FileUtils.DecompressFile(Path.Combine(Program.DataPath, FolderName + @"\Microsoft.VC90.CRT.manifest"),
Resources.x86.X86Resources.Microsoft_VC90_CRT_manifest);
FileUtils.DecompressFile(Path.Combine(Program.DataPath, FolderName + @"\msvcm90.dll"), Resources.x86.X86Resources.msvcm90_dll);
FileUtils.DecompressFile(Path.Combine(Program.DataPath, FolderName + @"\msvcp90.dll"), Resources.x86.X86Resources.msvcp90_dll);
FileUtils.DecompressFile(Path.Combine(Program.DataPath, FolderName + @"\msvcr90.dll"), Resources.x86.X86Resources.msvcr90_dll);
FileUtils.DecompressFile(Path.Combine(Program.DataPath, FolderName + @"\AlphaVSS.51.x86.dll"), Resources.x86.X86Resources.AlphaVSS_51_x86_dll);
FileUtils.DecompressFile(Path.Combine(Program.DataPath, FolderName + @"\AlphaVSS.52.x86.dll"), Resources.x86.X86Resources.AlphaVSS_52_x86_dll);
FileUtils.DecompressFile(Path.Combine(Program.DataPath, FolderName + @"\AlphaVSS.60.x86.dll"), Resources.x86.X86Resources.AlphaVSS_60_x86_dll);
}
FileUtils.DecompressFile(Path.Combine(Program.DataPath, FolderName + @"\AlphaVSS.Common.dll"), Resources.VssResourcesCommon.AlphaVSS_Common_dll);
FileUtils.DecompressFile(Path.Combine(Program.DataPath, FolderName + @"\ClientDataSnapshotVssAgent.exe"), Resources.VssResourcesCommon.ClientDataSnapshotVssAgent_exe);
}
现在我的代码中有一个代理程序exe在temp文件夹中运行,它引用了那些提取的dll,但是你可以轻松地使用你的P / Invoke并指定你在P / Invoke签名中提取它的完整路径。 / p>
作为一个额外的提示,我编写了一个小程序,它将简单地gzip传入的任何文件,然后我将以下内容放入代理程序的Post-build事件中。
"$(SolutionDir)\DataCompressor\DataCompressor.exe" "$(TargetPath)" "$(SolutionDir)\ClientDataSnapshot\VSS\Resources\$(TargetFileName).gz"
您可以为您的本机dll执行类似的后期构建事件,只需在每次完成构建时更新托管项目中的gz文件,并确保本机dll位于构建顺序中的托管dll之前,您将始终拥有最新的副本作为托管项目中的资源。
using System;
using System.IO;
using System.IO.Compression;
namespace DataCompressor
{
class Program
{
//This program is used to compress the compiled VssAgent for storage in the snapshot program
static void Main(string[] args)
{
//Will quit directly if any args are invalid.
ValidateArgs(args);
using (var sourceFile = File.OpenRead(args[0]))
using (var destFile = new FileStream(args[1], FileMode.Create))
using (var gz = new GZipStream(destFile, CompressionMode.Compress))
{
sourceFile.CopyTo(gz);
}
}
private static void ValidateArgs(string[] args)
{
if (args.Length == 2)
{
if (File.Exists(args[0]) == false)
{
Console.Error.WriteLine("The source file did not exist.");
Environment.Exit(-2);
}
if (Directory.Exists(Path.GetDirectoryName(args[1])) == false)
{
Console.Error.WriteLine("The destination directory did not exist.");
Environment.Exit(-3);
}
}
else
{
Console.Error.WriteLine("You must pass two arguments.");
Environment.Exit(-1);
}
}
}
}
答案 2 :(得分:0)
我最近遇到了类似的问题,其中C ++ / CLI DLL中的Native C代码运行速度非常慢。事实证明Visual Studio正在将我的C函数编译为Managed。
为了解决这个问题,我们使用Pragma unmanaged强制进行本机编译。这样就恢复了速度,而无需在不使用CLI的情况下将Native代码移动到自己的DLL中
// Force native compilation
#pragma managed(push, off)
// Your native code
void Foo()
{
}
// Restore managed compilation
#pragma managed(push, on)
答案 3 :(得分:-1)
您可以在.NET中使用相同的程序集混合语言,但不是很自然。除非绝对必要,否则我会避免这种情况。
请参阅:
我将不同语言的程序集分开。
答案 4 :(得分:-1)
我无法知道您可以用来组合用C#编写的托管代码和用C ++(或任何语言)编写的本机代码。您最接近的是在单个程序集中使用带有托管C ++的本机C ++,您可以说这会导致代码中的资金减速。