Как я могу запустить программу из памяти в C #? - PullRequest
1 голос
/ 27 февраля 2009

У меня есть какое-то приложение пользовательского интерфейса, которое живет в панели задач пользователя, написанной на C #. EXE-файл для этого инструмента зарегистрирован в нашей системе контроля версий в ряде проектов, в которых он используется, поэтому мы можем обновить версию, с которой он работает, установив обновленный EXE-файл.

Проблема в том, что когда пользователи получают последнюю версию exe, программа часто запускается, и на их компьютере происходит сбой синхронизации. Я хочу исправить это, чтобы программа не блокировала exe и любые зависимые DLL при запуске, чтобы они могли синхронизироваться без необходимости выключения программы.

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

Код, который я сейчас имею, выглядит примерно так:

public class ExecuteFromMemory
{
    public static void Main(string[] args)
    {
        //Figure out the name of the EXE to launch and the arguments to forward to it
        string fileName = args[0];
        string[] realArgs = new string[args.Length - 1];
        Array.Copy(args, 1, realArgs, 0, args.Length - 1);

        //Read the assembly from the disk
        byte[] binary = File.ReadAllBytes(fileName);

        //Execute the loaded assembly using reflection
        Assembly memoryAssembly = null;
        try
        {
            memoryAssembly = Assembly.Load(binary);
        }
        catch (Exception ex)
        {
            //Print error message and exit
        }

        MethodInfo method = memoryAssembly.EntryPoint;
        if (method != null && method.IsStatic)
        {
            try
            {
                method.Invoke(null, new object[] { realArgs });
            }
            catch(Exception ex)
            {
                //Print error message and exit
            }
        }
        else
        {
            //Print error message and exit
        }
    }
}

У меня вопрос, я делаю что-то совершенно глупое? Есть ли лучший способ справиться с этим? Если нет, что я должен сделать для поддержки обработки внешних зависимостей?

Например, приведенный выше код не может загрузить любые зависимые файлы, если вы попытаетесь запустить «Foo.exe», который использует функции из «Bar.dll», «Foo.exe» будет перезаписан, но «Bar.dll» 'все еще заблокирован и не может быть перезаписан.

Я попытался получить список сборок, на которые есть ссылки, из метода GetReferencedAssemblies () загруженного ассемблера, но, похоже, это не дает никаких указаний, откуда следует загружать сборки ... Нужно ли искать их сам? Если да, то как лучше это сделать?

Похоже, другие люди уже сталкивались с этим раньше, и я не хочу заново изобретать колесо.

- Обновить: EXE-файл зарегистрирован, потому что именно так мы распространяем наши собственные инструменты командам, которые их используют. Это не оптимально для этого варианта использования, но у меня нет возможности изменить эту политику.

Ответы [ 3 ]

4 голосов
/ 27 февраля 2009

Отказ от ответственности: я не использую Windows, хотя я знаком с ее странным способом блокировки вещей.

Чтобы обновить приложение во время его работы, вам, вероятно, понадобится два процесса: сам исполняемый файл и приложение-помощник для обновления, которое завершит процесс обновления. Допустим, ваше приложение - ProcessA.exe, а помощник по обновлению - Updater.exe. Ваша основная программа загрузит новую копию исполняемого файла, сохранив ее со случайным именем. Затем вы запускаете программу обновления, которая следит за прекращением текущего процесса. Когда ваш процесс завершается, он отображает быстрое окно, отображающее состояние обновления, перемещая новый исполняемый файл на место старого и затем перезапуская эту программу.

Было бы более элегантно иметь возможность эмулировать семантику файловой системы POSIX и иметь возможность удалить работающий в настоящее время образ диска процесса и заменить его новым файлом, но я не знаю, возможно ли это даже в Windows , В системе POSIX вы можете удалить используемый файл, и он не будет фактически удален до тех пор, пока не будут закрыты все оставшиеся файловые дескрипторы, хотя вы можете затем повторно использовать имя файла.

Возможно, вы захотите проверить статью, написанную на CodeProject , в которой говорит об этом . У этого также есть последующая статья .

Удачи!

1 голос
/ 27 февраля 2009

Нужно ли программе продолжать работу во время обновления?

Обычно для обновления работающей программы вы копируете любые файлы, которые должны быть заменены, во временную папку. Затем закройте старый экземпляр, удалите его и переместите новые файлы в правильные местоположения, затем перезапустите его.

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

0 голосов
/ 27 февраля 2009

Хотя ответ Михаэля является одним из способов сделать это, существуют инструменты, которые явно предназначены для управления тем, что установлено на рабочем столе.

То, что вы делаете с проверкой исполняемого файла в системе контроля версий, не нормально. Если у вас есть контроллер домена Windows, вы можете использовать групповую политику для передачи программ клиенту. В качестве альтернативы, вы можете использовать что-то вроде Altiris, чтобы справиться с этим.

Если вы должны продолжать идти своим путем, у вас есть два варианта. Во-первых, с помощью приложения-помощника / загрузчика, которое проверяет версию при запуске. Это похоже на то, как работает Firefox.

Второй способ - создать вспомогательный сервис, который находится в памяти и периодически опрашивает обновления. Так работают Google Chrome, Adobe и т. Д.

...