Альтернатива ILMerge, как встроить зависимые библиотеки приложения в файл EXE? - PullRequest
2 голосов
/ 21 марта 2011

Как указано здесь я пытаюсь внедрить dll в приложение exe для того, чтобы просто распространять один exe, но когда я пытаюсь запустить свое приложение на компьютере xp с полностью установленным .NET 4, оно просто вылетает без ошибок, я помещаю следующий код в метод main

[STAThread]
        static void Main()
        {
            AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
            {
                String resourceName = "AssemblyLoadingAndReflection." + new AssemblyName(args.Name).Name + ".dll";

                using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
                {
                    Byte[] assemblyData = new Byte[stream.Length];
                    stream.Read(assemblyData, 0, assemblyData.Length);
                    return Assembly.Load(assemblyData);
                }
            };

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new frmrPrincipal());
        }

У меня есть папка с именем dll, куда я помещаю

Functions.Shared.dll
Alex.UI.dll
Alex.Controls.dll

и я устанавливаю его действие «Встроенный ресурс».

если я удаляю этот кусок кода и устанавливаю dll для включения одним щелчком мыши, как только установщик работает нормально. Кстати. Использование .NET Framework 4 Полный профиль и VS2010 SP1

Ответы [ 4 ]

3 голосов
/ 21 марта 2011

Дрожание становится kaboom, когда он пытается использовать метод Main (). AssemblyResolve еще не зарегистрирована, проблема с курицей и яйцом. Вы можете использовать только доступные в Main типы, поэтому вам следует держаться подальше от frmrPrincipal. Использование небольшого вспомогательного метода может решить эту проблему, но теперь вам придется подавить встраивание с помощью [MethodImpl]. Вы также стреляете ногой, не позволяя ngen.exe выполнять свою работу.

using System.Runtime.CompilerServices;
...
    [STAThread]
    static void Main()
    {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        {
            // etc..
        }
        AvoidJitterBombing();
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    private static void AvoidJitterBombing() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new frmrPrincipal());
    }
0 голосов
/ 15 мая 2012

Я подозреваю, что вы пытаетесь загрузить DLL с неуправляемым кодом. Для управляемых библиотек достаточно просто прочитать и загрузить сборку в память, или вы можете загрузить из определенного места, даже не читая. Для сборок в смешанном режиме я добился успеха только путем записи байтов в файл и загрузки из его местоположения.

class Program
{
    [STAThread]
    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);
        };

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new frmrPrincipal());
    }
}

где Program - имя класса. Чтобы избежать проблемы с курицей и яйцом, необходимо убедиться, что вы объявили обработчик перед доступом к сборке, и чтобы у вас не было доступа к элементам сборки (или к созданию экземпляров всего, что имеет отношение к сборке) внутри загрузочной (разрешающей сборку) детали. Также убедитесь, что GetMyApplicationSpecificPath() не является каким-либо временным каталогом, поскольку временные файлы могут пытаться стереть другие программы или вы сами (не то, что он будет удален, когда ваша программа обращается к dll, но, по крайней мере, это создает неудобства. AppData это хорошее место). Также обратите внимание, что вы должны записывать байты каждый раз, вы не можете просто загрузить из местоположения только потому, что там уже находится dll.

0 голосов
/ 22 марта 2011

Вы можете взглянуть на .NETZ , который мы использовали для развертывания приложений WinForms вместе с ClickOnce.

0 голосов
/ 21 марта 2011

Я играл с этим недавно, начиная с этого или очень похожего фрагмента кода, и я думаю, что конструкция resourceName неверна. Попробуйте установить точку останова в начале метода разрешения, а затем вызвать GetManifestResourceNames() в исполняющей сборке, чтобы увидеть, какое имя она фактически дает встроенным ресурсам.

Я подозреваю, что это, вероятно, "dlls.Functions.Shared" и т. Д. Вместо "AssemblyLoadingAndReflection.Functions.Shared"

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...