web-dev-qa-db-ja.com

C ++ windows dllをC#アプリケーションexeにマージするにはどうすればよいですか?

データI/OにC++ dllを使用するWindows C#プログラムがあります。私の目標は、アプリケーションを単一のEXEとして展開することです。

このような実行可能ファイルを作成する手順は何ですか?

35
Noah

2007年2月4日(日曜日)マネージコードとアンマネージコードの単一アセンブリ展開

.NET開発者はXCOPYデプロイメントが大好きです。また、単一のアセンブリコンポーネントが大好きです。コンポーネントを使用する必要があり、そのコンポーネントのメインアセンブリにも含めるファイルのリストを覚えておく必要がある場合は、少なくとも常に不安を感じます。したがって、最近マネージコードコンポーネントを開発する必要があり、Cからアンマネージコードを追加する必要があったときDLL(これを手伝ってくれてMarcus Heegeに感謝!) 2つのDLLを簡単に展開できるようにします。これが2つのアセンブリだけの場合、ILmergeを使用してそれらを1つのファイルにまとめることができます。ただし、これは、マネージDLLとアンマネージDLLが混在するコードコンポーネントでは機能しません。

だから私は解決策のために思いついたものです:

組み込みリソースとして、コンポーネントのメインアセンブリで展開するDLLを含めます。次に、クラスコンストラクターを設定して、以下のようにDLLを抽出します。クラスctorは各AppDomain内で1回だけ呼び出されるため、オーバーヘッドは無視できると思います。

namespace MyLib
{
    public class MyClass
    {
        static MyClass()
        {
            ResourceExtractor.ExtractResourceToFile("MyLib.ManagedService.dll", "managedservice.dll");
            ResourceExtractor.ExtractResourceToFile("MyLib.UnmanagedService.dll", "unmanagedservice.dll");
        }

        ...

この例では、リソースとして2つのDLLを含めました。1つはアンマネージコードDLLで、もう1つはマネージコードですDLL(デモ目的のみ))、この手法が両方の種類でどのように機能するかを示しますコードの。

DLLを独自のファイルに抽出するコードは簡単です。

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属性を使用します。例えば.

[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

18
Nick

Fody.Costuranugetを使用します

  1. ソリューションを開く->プロジェクト-> Nugetパッケージを管理する
  2. Fody.Costuraを検索します
  3. コンパイルあなたのプロジェクト

それでおしまい !

出典: http://www.manuelmeyer.net/2016/01/net-power-tip-10-merging-assemblies/

3
automan

試してみてください boxedapp ;メモリからすべてのDLLをロードできます。また、.netランタイムを埋め込むこともできるようです。本当にスタンドアロンのアプリケーションを作成するのに良い...

3
Art

Visual Studioでプロジェクトを右クリックし、[プロジェクトのプロパティ]-> [リソース]-> [リソースの追加]-> [既存のファイルの追加]を選択します。そして、App.xaml.csまたは同等のものに以下のコードを含めます。

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);
}

これが私の元のブログ投稿です: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-Assembly/

2

ILMergeを試しましたか? http://research.Microsoft.com/~mbarnett/ILMerge.aspx

ILMergeは、複数の.NETアセンブリを単一のアセンブリにマージするために使用できるユーティリティです。 Microsoft .NET Framework Developer CenterのTools&Utilitiesページから無料で利用できます。

C++をビルドしている場合DLL with /clrフラグ(すべてまたは一部がC++/CLI)の場合、機能するはずです。

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

ただし、通常の(ネイティブ)Windowsでは機能しませんDLL。

1
Raithlin

Smart Assembly はこれ以上のことができます。 DLLにアンマネージコードがある場合、DLLを単一のアセンブリにマージできません。代わりに、必要な依存関係をリソースとしてメインexeに埋め込むことができます。その裏側、それは無料ではありません。

リソースにdllを埋め込み、AppDomainのアセンブリResolveHandlerに依存することで、これを手動で行うことができます。混合モードのdllに関しては、ResolveHandlerアプローチの多くのバリアントとフレーバーが機能しないことがわかりました(すべてdllバイトをメモリに読み取り、そこから読み取ります)。それらはすべてマネージdllで機能しました。これが私のために働いたものです:

_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のロード方法について、この link または this を確認できます。

0
nawfal

Thinstall は1つのソリューションです。ネイティブWindowsアプリケーションの場合、DLLをバイナリリソースオブジェクトとして埋め込み、必要になる前に実行時に抽出することをお勧めします。

0
titanae