1

次のコードを使用して実行時に dll ライブラリをロードしようとしています。これにより、メインの実行可能ファイルと共に多くの dll ファイルをユーザーに提供する必要がなくなります。すべての dll ファイルを埋め込みリソースとしてインクルードし、参照部分にもそれらをインクルードし、CopyLocalプロパティを false に設定しました。しかし、ここでの問題は次のとおり
です。 1. すべての dll が Bin\Debug フォルダーにコピーされます
2. FileNotFoundExceptionが発生します。
これらの問題を解決するために多くの検索を行い、最終的にここにいます。ここで同様のコードを取得しましたが、まだ何もできませんでした。この例外を防ぐにはどうすればよいですか...?? Windowsフォームアプリケーション(WPFではない)に対して同じことを行うより良い方法はありますか...??

using System;
using System.Linq;
using System.Windows.Forms;
using System.Diagnostics;
using System.Reflection;
using System.Collections.Generic;
using System.IO;

namespace MyNameSpace
{
    static class Program
    {
        static int cnt;
        static IDictionary<string, Assembly> assemblyDictionary;
        [STAThread]
        static void Main()
        {
            AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
            if (cnt != 1)
            {
                cnt = 1;
                Assembly executingAssembly = Assembly.GetExecutingAssembly();
                string[] resources = executingAssembly.GetManifestResourceNames();
                foreach (string resource in resources)
                {
                    if (resource.EndsWith(".dll"))
                    {
                        using (Stream stream = executingAssembly.GetManifestResourceStream(resource))
                        {
                            if (stream == null)
                                continue;

                            byte[] assemblyRawBytes = new byte[stream.Length];
                            stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
                            try
                            {
                                assemblyDictionary.Add(resource, Assembly.Load(assemblyRawBytes));
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show("Failed to load: " + resource + " Exception: " + ex.Message);
                            }
                        }
                    }
                }
                Program.Main();
            }
            if (cnt == 1)
            {
                cnt = 2;
                System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Highest;
                Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
                Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new MainForm());
            }
        }

        private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
        {            
            AssemblyName assemblyName = new AssemblyName(args.Name);

            string path = assemblyName.Name + ".dll";

            if (assemblyDictionary.ContainsKey(path))
            {
                return assemblyDictionary[path];
            }
            return null;
        }
    }
}

コードで不必要に何かを使用している場合は、正しい方法を教えてください...私は、論文を提出するためにWindows フォーム アプリケーション v4.0プロジェクトに取り組んでいる学生です。

4

2 に答える 2

1

それでもこれを行う必要がある場合は、この OnResolveAssembly メソッドを使用します。したくない場合は、それらを配列にプリロードする必要はありません。これにより、実際に必要になったときに初めて読み込まれます。

それからちょうど:

  • some.assembly.dllファイルをプロジェクトに追加します。
    • おそらくプロジェクトの出力への参照ではありません
    • しかし、DLL プロジェクトの結果であるファイルです。
  • ファイルのプロパティでリソースとしてマークします。

    // This function is not called if the Assembly is already previously loaded into memory.
    // This function is not called if the Assembly is already in the same folder as the app.
    //
    private static Assembly OnResolveAssembly(object sender, ResolveEventArgs e)
    {
        var thisAssembly = Assembly.GetExecutingAssembly();
    
        // Get the Name of the AssemblyFile
        var assemblyName = new AssemblyName(e.Name);
        var dllName = assemblyName.Name + ".dll";
    
        // Load from Embedded Resources
        var resources = thisAssembly.GetManifestResourceNames().Where(s => s.EndsWith(dllName));
        if (resources.Any())
        {
            // 99% of cases will only have one matching item, but if you don't,
            // you will have to change the logic to handle those cases.
            var resourceName = resources.First();
            using (var stream = thisAssembly.GetManifestResourceStream(resourceName))
            {
                if (stream == null) return null;
                var block = new byte[stream.Length];
    
                // Safely try to load the assembly.
                try
                {
                    stream.Read(block, 0, block.Length);
                    return Assembly.Load(block);
                }
                catch (IOException)
                {
                    return null;
                }
                catch (BadImageFormatException)
                {
                    return null;
                }
            }
        }
    
        // in the case the resource doesn't exist, return null.
        return null;
    }
    

-ジェシー

PS: これはhttp://www.paulrohde.com/merging-a-wpf-application-into-a-single-exe/からのものです。

于 2013-10-17T00:54:06.803 に答える
0

次のことを試してください。

  • 各 .dll リソースについて:
    • ファイルがすでに に存在する場合はAppDomain.Current.BaseDirectory、次のリソースに進みます
    • それ以外の場合は、リソースを に保存しAppDomain.Current.BaseDirectoryます。これを try-catch で実行し、失敗した場合はユーザーに通知します。この手順を正常に完了するには、インストール フォルダー (通常は「Program Files」のサブフォルダー) への書き込みアクセスが必要です。これは、ファイルがファイル システムに書き込まれている場合に限り、最初に管理者としてプログラムを実行することで解決されます。
  • アセンブリが VS プロジェクトによって参照されている場合は、それらを自分で読み込む必要はありません。この作業の理由を理解するには、アセンブリが CLR によってどのように配置されるかを理解する必要があります。
  • それ以外の場合は、パラメータとしてまたは およびのいずれかを取るAssembly.Loadのいずれかを使用して、各アセンブリを自分でロードする必要があります。stringAssemblyName
于 2012-11-19T09:11:19.757 に答える