首页 / 知识

如何将C ++ Windows dll合并到C#应用程序exe中?

2023-04-15 22:17:00

如何将C ++ Windows dll合并到C#应用程序exe中?

How can a C++ windows dll be merged into a C# application exe?

我有一个Windows C#程序,该程序使用C ++ dll进行数据I / O。 我的目标是将应用程序部署为单个EXE。

创建此类可执行文件的步骤是什么?


托管和非托管代码的单程序集部署
2007年2月4日,星期日

.NET开发人员喜欢XCOPY部署。而且他们喜欢单一装配部件。如果我必须使用某个组件并且需要记住一个文件列表,该文件也要包含在该组件的主程序集中,至少我总会感到不安。因此,当我最近不得不开发托管代码组件并用来自C DLL的一些非托管代码对其进行扩充时(向Marcus Heege表示感谢,以帮助我解决这个问题!),我想到了如何简化两个DLL的部署。 。如果这只是两个程序集,我本可以使用ILmerge将它们打包在一个文件中。但这不适用于具有托管和非托管DLL的混合代码组件。

所以这是我想出的解决方案:

我将要与组件主装配一起部署的所有DLL都包含在内,作为嵌入式资源。
然后,我设置了一个类构造函数以提取这些DLL,如下所示。我认为,类ctor在每个AppDomain中仅被调用一次,因此这是一个可忽略的开销。

1
2
3
4
5
6
7
8
9
10
11
namespace MyLib
{
    public class MyClass
    {
        static MyClass()
        {
            ResourceExtractor.ExtractResourceToFile("MyLib.ManagedService.dll","managedservice.dll");
            ResourceExtractor.ExtractResourceToFile("MyLib.UnmanagedService.dll","unmanagedservice.dll");
        }

        ...

在此示例中,我包括两个DLL作为资源,一个是非托管代码DLL,一个是托管代码DLL(仅用于演示目的),以说明该技术如何在两种代码中起作用。

将DLL提取到自己的文件中的代码很简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static class ResourceExtractor
{
    public static void ExtractResourceToFile(string resourceName, string filename)
    {
        if (!System.IO.File.Exists(filename))
            using (System.IO.Stream s = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
                using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Create))
                {
                    byte[] b = new byte[s.Length];
                    s.Read(b, 0, b.Length);
                    fs.Write(b, 0, b.Length);
                }
    }
}

像这样使用托管代码程序集与平常相同-几乎一样。您在组件的主项目(此处为MyLib)中引用它(此处为ManagedService.dll),但是将"复制本地"属性设置为false。另外,您可以在装配中将其链接为现有项,并将"生成操作"设置为"嵌入式资源"。

对于非托管代码(在这里:UnmanagedService.dll),您只需将DLL作为现有项链接,然后将"生成操作"设置为"嵌入式资源"。要访问其功能,请照常使用DllImport属性,例如

1
[DllImport("unmanagedservice.dll")] public extern static int Add(int a, int b);

而已!一旦使用静态ctor创建该类的第一个实例,嵌入式DLL就会被提取到它们自己的文件中,并可以像将它们作为单独的文件部署一样使用。只要您对执行目录具有写许可权,这对您就可以正常工作。至少对于原型代码,我认为这种单程序集部署方式非常方便。

请享用!

http://weblogs.asp.net/ralfw/archive/2007/02/04/single-assembly-deployment-of-managed-and-unmanaged-code.aspx


使用Fody.Costura nuget

  • 打开您的解决方案->项目->管理Nuget包
  • 搜索Fody.Costura
  • 编译您的项目。
  • 而已 !

    Source:

    .NET Power Tip 10: Merging Assemblies


    尝试boxedapp;它允许从内存加载所有DLL。另外,似乎您甚至可以嵌入.net运行时。创建一个真正独立的应用程序非常好...


    只需在Visual Studio中右键单击您的项目,然后选择项目属性->资源->添加资源->添加现有文件…
    并将下面的代码包含到您的App.xaml.cs或等效文件中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public App()
    {
        AppDomain.CurrentDomain.AssemblyResolve +=new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    }

    System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll","");

        dllName = dllName.Replace(".","_");

        if (dllName.EndsWith("_resources")) return null;

        System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace +".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());

        byte[] bytes = (byte[])rm.GetObject(dllName);

        return System.Reflection.Assembly.Load(bytes);
    }

    这是我的原始博客文章:

    Embed managed dlls easily in a .NET assembly


    您是否尝试过ILMerge? http://research.microsoft.com/~mbarnett/ILMerge.aspx

    ILMerge is a utility that can be used to merge multiple .NET assemblies into a single assembly. It is freely available for use from the Tools & Utilities page at the Microsoft .NET Framework Developer Center.

    如果要使用/clr标志(全部或部分C ++ / CLI)构建C ++ DLL,则它应该可以工作:

    1
    ilmerge /out:Composite.exe MyMainApp.exe Utility.dll

    但是,它不适用于普通(本机)Windows DLL。


    智能装配可以完成更多任务。如果您的dll具有不受管的代码,则它不会让您将dll合并到单个程序集中,而是可以将所需的依赖项作为资源嵌入到主exe中。它的另一面,不是免费的。

    您可以通过将dll嵌入到资源中,然后依靠AppDomain的Assembly ResolveHandler来手动执行此操作。当涉及混合模式dll时,我发现ResolveHandler方法的许多变体和风格对我不起作用(所有将dll字节读取到内存并从中读取)的方法。他们都为托管dll工作。这对我有用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    static void Main()
    {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        {
            string assemblyName = new AssemblyName(args.Name).Name;
            if (assemblyName.EndsWith(".resources"))
                return null;

            string dllName = assemblyName +".dll";
            string dllFullPath = Path.Combine(GetMyApplicationSpecificPath(), dllName);

            using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace +".Resources." + dllName))
            {
                byte[] data = new byte[stream.Length];
                s.Read(data, 0, data.Length);

                //or just byte[] data = new BinaryReader(s).ReadBytes((int)s.Length);

                File.WriteAllBytes(dllFullPath, data);
            }

            return Assembly.LoadFrom(dllFullPath);
        };
    }

    此处的关键是将字节写入文件并从文件位置加载。为了避免出现鸡蛋问题,您必须确保在访问程序集之前声明处理程序,并且不要在装入(程序集解析)零件中访问程序集成员(或实例化必须处理该程序集的任何内容)。还要注意确保GetMyApplicationSpecificPath()不是任何临时目录,因为临时文件可能会被其他程序或您自己擦除(不是在您的程序访问dll时会删除临时文件,但至少会造成麻烦)。 AppData位置不错)。另请注意,您每次必须写入字节,无法从位置加载,因为dll已驻留在该位置。

    如果程序集完全不受管,则可以看到此链接或有关如何加载此类dll的信息。


    Thinstall是一种解决方案。对于本机Windows应用程序,我建议将DLL嵌入为二进制资源对象,然后在需要时在运行时将其提取。


    Xenocode的PostBuild可以将托管和非托管打包到一个exe中。


    应用程序数据目标步骤

    最新内容

    相关内容

    猜你喜欢