将本机DLL和程序集合并到一个DLL中

时间:2009-12-06 03:58:45

标签: c# .net c++ dll

我目前正在用C ++和C#编程。使用本机C ++进行数值计算部分。

最初我打算使用C ++ / CLI来创建本机C ++类的包装器,但我发现它会导致2到4倍的减速。

所以我决定将我的原生C ++编译成DLL,并通过P/Invoke调用.NET / C#。我将在C#中进行数据预处理,并在本机DLL中进行数字运算。

问题在于,当我将作品交给他人使用时,我希望它是一个单独的DLL。

这可能吗?顺便说一下,我有原生C ++的所有源代码。

5 个答案:

答案 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中使用相同的程序集混合语言,但不是很自然。除非绝对必要,否则我会避免这种情况。

请参阅:

http://www.hanselman.com/blog/MixingLanguagesInASingleAssemblyInVisualStudioSeamlesslyWithILMergeAndMSBuild.aspx

我将不同语言的程序集分开。

答案 4 :(得分:-1)

我无法知道您可以用来组合用C#编写的托管代码和用C ++(或任何语言)编写的本机代码。您最接近的是在单个程序集中使用带有托管C ++的本机C ++,您可以说这会导致代码中的资金减速。