Delphi как перезапустить приложение
По какой-то причине или выбранный пользователем "попросите" текущее приложение перезапустить его самостоятельно.
спросил(а) 2011-05-16T20:11:00+04:00 10 лет, 6 месяцев назад ответил(а) 2011-05-16T20:14:00+04:00 10 лет, 6 месяцев назадЯ могу добавить к ответу @Andreas Rejbrand:
Если код выполняется в файле .dpr до Application.Initialize. для меня, лучше называть Halt(0) вместо Application.Terminate . Мне это нужно, потому что в первой программе запуска выполняется некоторая установка, а затем перезапускается. Если я вызываю Application.Terminate , основная форма мигает в течение секунды (но ее вообще не следует создавать!), А затем приложение закрывается. Поэтому мой код выглядит следующим образом:
Существует еще один способ закрытия-перезапуска приложения:
Сохранить запланированную задачу за короткое время после закрытия приложения. Это должно быть ОЧЕНЬ ПОСЛЕДНЯЯ вещь, которую ваше приложение делает перед выходом (без дальнейшей обработки, сохранения, выгрузки и т.д.)
-
сначала получить системное время
установить запланированное задание через некоторое время после этого времени (запланированное событие должно будет запустить ваш исполняемый файл)
выйти из приложения (закрытие основной формы или application.terminate сделает это)
Когда ваша программа запустится снова, она должна проверить любую запланированную задачу и удалить ее. Это должно быть действие VERY FIRST, которое ваше приложение должно делать при запуске. (Очистка)
-
проверить любые запланированные задачи, созданные вашим исполняемым файлом
удалить их
AFAIK, у компонента компонентов Delphi Jedi есть компонент, с которым вы можете выполнять планирование задач.
ответил(а) 2011-05-17T10:44:00+04:00 10 лет, 6 месяцев назадУ вас может быть отдельная простая программа restart.exe, которую вы запускаете из своей программы и передаете ей имя исполняемого файла. Затем закройте свою программу. Программа перезапуска может подождать некоторое время или до тех пор, пока исполняемый файл не будет прочитан для записи, что, по-видимому, означает, что он не работает, тогда он может выполнить его и закрыть сам.
Я ожидаю, что есть лучший способ сделать это, может быть, кто-то может предоставить лучшее решение, но эта функция, похоже, говорит мне, выполняется ли исполняемый файл:
Не должно быть возможности запускать несколько экземпляров моего приложения. Таким образом, исходный код проекта содержит:
Теперь я хочу программно перезапустить свое приложение. Обычный способ:
Но в моем случае это не сработает из-за мьютекса. Даже если я отпущу мьютекс перед запуском второго экземпляра, он не сработает, потому что завершение работы занимает некоторое время, и два экземпляра не могут работать параллельно (из-за общих ресурсов и других эффектов).
Есть ли способ перезапустить приложение с такими характеристиками? (По возможности без дополнительного исполняемого файла)
Возможно, вам следует мыслить нестандартно. Вместо того, чтобы возиться с логикой мьютекса / экземпляра, вы можете просто создать другой исполняемый файл, который ожидает закрытия вашего приложения, а затем запускает его снова. В качестве дополнительного бонуса вы можете позже использовать этот механизм, например, для обновления некоторых двоичных файлов вашего основного приложения. Кроме того, гораздо проще запускать его с повышенными правами вместо поддержания разных уровней целостности внутри одного и того же приложения и т. Д.
Почему нельзя просто отпустить мьютекс перед попыткой перезапуска? Если по какой-то случайности другой экземпляр запускается перед тем, который вы явно вызываете с перезапуском, который не имеет значения, ваше приложение все равно будет запущено и снова запустится с любыми внесенными изменениями, которые потребовали перезапуска. Я не думаю, что вам нужна сложность других решений.
Включите в свой ShellExecute какой-нибудь параметр, например / WaitForShutDown, и создайте еще один мьютекс. В вашей программе перед инициализацией, например, в ее файле .dpr, вставьте что-то вроде:
If (Pos ('/ WaitForShutDown', CmdLine) <> 0) then WaitForSingleObject (ShutDownMutexHandle, INFINITE);
Кроме того, в свою программу после всех доработок и выпуска общих ресурсов включите что-то вроде
ХОРОШО. Теперь я верю, что знаю, в чем ваша проблема . У вас проблемы с доработкой программных модулей!
Попробуйте добавить в раздел программы как первый модуль мой нижний модуль RestartMutex.
Если вы хотите перезапустить приложение, просто установите для переменной Restart значение true, а затем закройте приложение.
Итак, поскольку RestartMutex добавлен первым в разделе программы, это будет означать, что завершение модуля RestartMutex будет выполнено почти в конце закрытия приложения, а все остальные модули будут выполнять завершение перед модулем RestartMutex, что означает, что приложение может снова запуститься безопасно!
Вы можете передать аргумент командной строки, например «перезапуск», и запустить Sleep (), прежде чем пытаться получить мьютекс или попытаться получить мьютекс в цикле, который некоторое время находится в спящем режиме.
Также вы можете настроить связь между обоими процессами, но это может быть излишним.
Привет, прочтите следующую статью Зарко Гаджича - там вы получить несколько идей, образец кода и даже целый компонент для использования.
Ваш ReleaseMutex вероятно сбой, поскольку вы передаете 'False' для 'bInitialOwner' при вызове CreateMutex . Либо имеете первоначальное право собственности на мьютекс, либо звоните CloseHandle вместо ReleaseMutex передает ваш дескриптор мьютекса.
Оформить заказ таким образом:
Просто запускает новое приложение и закрывает текущее;
(побеждая идею сна)
Если вы хотите убедиться, что исходный процесс действительно завершен / закрыт, прежде чем вы создадите мьютекс, то одна из идей - передать PID новому процессу (командная строка является самой простой, любой другой метод IPC также работает), затем используйте OpenProcess (SYNCHRONIZE, false, pid) и WaitForSingleObject (я бы использовал цикл с тайм-аутом (100 мс - хорошее значение) и действовал бы соответственно, если исходный процесс слишком долго закрывается)
В конце концов, помимо вышесказанного, я также создал процедуру RestartSelf в том же модуле с мьютексом и выполнял там логику, чтобы сохранить единственный экземпляр и логику перезапуска в одном месте (параметр жестко закодирован , вы не хотите, чтобы жестко запрограммированный материал был разбросан по вашим приложениям.
невозможно запустить несколько экземпляров моего приложения. Поэтому источник проекта содержит:
теперь я хочу перезапустить приложение программно. Обычным способом было бы:--3-->
но это не будет работать в моем случае из-за мьютекса. Даже если я выпущу мьютекс перед запуском второго instace, он не будет работать, потому что завершение работы занимает некоторое время, и два экземпляра не могут работать параллельно (из-за общих ресурсов и других эффекты.)
есть ли способ перезапустить приложение с такими характеристиками? (Если возможно без дополнительного исполняемого файла)
Возможно, вам следует думать нестандартно. Вместо futzing с логикой мьютекса / экземпляра, вы можете просто создать другое исполняемый файл, который ждет закрытия вашего приложения, а затем запускает его снова. В качестве дополнительного бонуса вы можете позже использовать этот механизм, например, для обновления некоторых двоичных файлов вашего основного приложения. Также намного проще запустить его повышенным, а не поддерживать разные уровни целостности внутри одного приложения и т. д.
Почему вы не можете просто освободить мьютекс перед попыткой перезапуска? Если по какой-то случайности другой экземпляр запускается перед тем, который вы явно вызываете с перезапуском, который не имеет значения, у вас все равно будет ваше приложение снова запущено с любыми изменениями, которые потребовали перезапуска. Я не думаю, что вам нужна какая-либо сложность других решений.
включите в свой ShellExecute некоторый параметр, например, /WaitForShutDown и создайте еще один мьютекс. В вашей программе, перед инициализацией, например, в its .dpr файл, вставьте что-то вроде:
if (Pos ('/WaitForShutDown', CmdLine) 0) тогда WaitForSingleObject (ShutDownMutexHandle, INFINITE);
кроме того, в вашей программе, после все завершения и выпуска своих общих ресурсов, включая как
правка.
OK. Теперь я понимаю, в чем твоя проблема. У вас проблемы с доработкой программных блоков!
попробуйте добавить в раздел программы как первый блок мой нижний блок RestartMutex.
когда вы хотите перезапустить приложение просто установить переменную перезагрузка true и чем завершить приложение.
Итак, потому что RestartMutex добавлен как во-первых, в разделе программы это будет означать, что финализация unit RestartMutex будет завершена почти в конце закрытия приложения, а все остальные подразделения завершат работу до unit RestartMutex, что означает, что приложение может начать безопасно снова!
вы можете передать аргумент командной строки, например "restart" и запустить Sleep (), прежде чем пытаться получить мьютекс или попытаться получить мьютекс в цикле, который спит некоторое время.
также вы можете настроить связь между обоими процессами, но это может быть излишним.
привет, взгляните на следующие статьи by Zarko Gajic - там вы получите некоторые идеи, примеры кода и даже целый компонент для использования.
код ReleaseMutex вероятно, сбой, так как вы передаете "False" для "bInitialOwner" при вызове CreateMutex . Либо иметь начальное владение мьютексом, либо вызвать CloseHandle вместо "ReleaseMutex" передает ваш дескриптор мьютекса.
оформить заказ таким образом:
просто запускает новое приложение и убивает currernt;
(отбивая идею сна)
Если вы хотите, чтобы убедиться, что исходный процесс действительно прекращен/закрытые до создания мьютекса, то один из вариантов-передать PID нового процесса (командная строка-это самый простой, и любой другой МПК метод работает так же), а затем использовать для открытия процесса(синхронизация, ложь, пид) и waitforsingleobject (я бы использовать цикл с таймаутом (100 мс-это хорошее качество) и действовать соответственно, если исходный процесс занимает слишком много времени, чтобы закрыть)
Что я закончил помимо вышеизложенного, нужно было также создать процедуру RestartSelf в том же блоке с мьютексом и сделать логику там, чтобы сохранить один экземпляр и перезапустить логику в том же месте (параметр жестко закодирован, вы не хотите, чтобы жестко закодированные вещи были разбросаны вокруг вашего приложения(приложений).
Я не знаток Delphi, но по институту (а потом я перешёл на Builder :D ) помню, что в каждом pas файле можно создать четыре раздела:
unit Unit_name;interface
// код
implementation
// код
initialization
// код
finalization
// код
end.
1. interface. Производится объявление типов, классов, глобальных функций и объектов. Также подключаются другие модули (uses). Объявленные элементы доступны в других модулях
2. implementation. Всё тоже самое, но ещё производится реализация функций и методов классов. Объявленные элементы не доступны в других модулях
3. initialization. Указанная последовательность команд выполняется в момент запуска программы. Обратите внимание - здесь не объявляются функции или переменные - они вызываются так, как вызывались бы внутри функции
4. finalization. Указанная последовательность команд выполняется в момент завершения программы
OleCheck(CoGetMalloc(1, GlobalMalloc)); // Эта команда выполнится при запуске программы
finalization // начало блока завершения
GlobalMalloc := nil; // эта команда выполнится при завершении программы
end. // конец модуля :D
в любом случае успеешь выгрузиться
потому что если использовать ExitProcess то очень быстро вылетаешь из приложения
.
ну даже если не успеешь выгрузиться и ну что дальше.
[QUOTE=Ahilles]в любом случае успеешь выгрузиться
потому что если использовать ExitProcess то очень быстро вылетаешь из приложения
.
ну даже если не успеешь выгрузиться и ну что дальше. [/QUOTE]
Проблема в том, что "быстро вылетать" из приложения может быть вредно для самого приложения :( - ситуации бывают разные. Да и быстродействие у компьютеров может различаться.
Кроме того, если рассуждать "ну даже если не успеешь" и заниматься гаданием подобным на кофейной гуще, то лучше вообще отказаться от возможности автоматического перезапуска.
Лучше сделать так, как я предлагал, в отдельном либо главном модуле
Set_Running (true); // Установка флага запущенности программы
else begin
// Программа уже запущена - отменить повторный запуск программы
end;[/INDENT]finalization[INDENT]Set_Running (false); //Снятие флага запущенности программы
if (Need_Restarting) then // Проверка требования перезапуска
Restart_Program; //Перезапуск программы
[/INDENT]end.
Функции Test_Running, Set_Running и Restart_Program напишите сами. По крайней мере, алгоритмы для проверки запущенности программы приведены во многих книгах по программированию. мне кажется то, что предлагает el scorpio (или то, что я предложил) может понадобиться, если прога ищет себя по окнам или в процессах, а если проверять запущенность с помощью мьютексов, то в случае необходимости вызвать ReleaseMutex(потом то, что писал ahilles) и вновь запущенная прога работающую не обнаружит. kosfiz
Кстати, я тоже в расчёте на мьютексы и им подобное код писал. Только конкретную реализацию не расписывал el scorpio
мьютексы, на мой взгляд, лучший способ для определения того, запущена прога или нет.
я вам ещё раз повторяю приведённый код winexec/exitprocess в 99,99% случаев сработает
просто сами подумайте что быстрее уничтожение процесса + выгрузка его из памяти намного быстрее чем создание процесса + загрузка его в память + всякие инициилизации
просто сами подумайте что быстрее уничтожение процесса + выгрузка его из памяти намного быстрее чем создание процесса + загрузка его в память + всякие инициилизации
[/QUOTE]
Не факт, не факт :)
Статистика - вещь хорошая, но по закону подлости, ваша программа как раз и будет периодически попадать в оставшиеся 0.01% :D
Мой же способ сработает на все сто :cool: это тоже правильно
я как раз делал такую прогу и никгода не задумывался об 0.01%
[QUOTE=ahilles]это тоже правильно
я как раз делал такую прогу и никгода не задумывался об 0.01%[/QUOTE]
Зря, зря.
"Авоська" - парень добрый - или выручит, или выучит :D
Если неприятность может случится - она случается :D
Подобные закономерности, регулярно подтверждаемые практикой, любой специалист со стажем может цитировать десятками.
хмм. а если между закрытием проги и запуском её необходимо, например, файл проги обновить. verybadbugимеешь ввиду сам экзе файл обновить. тогда, наверное, по принципу прог, которые могут удалять сами себя, т.е. размещаешь в памяти, обновляешь файл, а потом перезапуск, вроде так, хотя может и ошибаюсь. Тогда ручками :). Или через вызов .bat файла.
Забить цикл копирования обновлённой версии в исходный файл. Условие выхода из цикла - безошибочный процесс копирования, или же - пока время создания файла не станет равным времени обновлённого.
А дальше - опять запуск программы. start /wait taskkill.exe /F /IM program.exe
copy newprog.exe program.exe
start program.exe taskkill - незнаю.
А если программа требует "правильного" закрытия. Например, при работе с одной БД через BDE, при прерывании работы программы, база данных продолжала считаться "открытой" - соответственно, ексклюзивный доступ к ней получался невозможным :(
Или же при завершении нужно сохранить данные в файл.
блин. вот тока не надо в крайности. моя прога не на столько тупая, чтобы перед вызовом этого BAT оставить открытую БД, несохраненные данные, невысвобожденную память и всё в таком духе.
[QUOTE=verybadbug]блин. вот тока не надо в крайности. моя прога не на столько тупая, чтобы перед вызовом этого BAT оставить открытую БД, несохраненные данные, невысвобожденную память и всё в таком духе. [/QUOTE]
Рад за вас. Но вот только даже самая "умная" прога всё равно использует объекты ОС и файлы, которые остаются открыты во время работы - а тут ей, ни с того, ни с сего - taskkill :(.
P.S.
А причём в батнике "start /wait"? Что это означает - я знаю; просто не могу понять - зачем?
очевидно, чтобы в памяти не висели две копии проги - и в этом я с verybadbug'ом согласен - потому что две копии проги в памяти - это неправильно.
Дело в том, что "start /wait" в батниках используется для ожидания завершения оконных приложений. Консольные же (к числу коих относится и
Читайте также: