Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Обновлние своей программы

39K
13 ноября 2008 года
YouROK
12 / / 27.10.2008
Вобщем есть программа все время висит в памяти, в папку в сети я скидываю новую версию программы, она должна сама себя обновить с этой папки.
Поделитесь как можно это сделать, желательно без дополнительных программ, у кого какие мысли?
288
13 ноября 2008 года
nikitozz
1.2K / / 09.03.2007
Цитата: YouROK
Вобщем есть программа все время висит в памяти, в папку в сети я скидываю новую версию программы, она должна сама себя обновить с этой папки.
Поделитесь как можно это сделать, желательно без дополнительных программ, у кого какие мысли?



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

87
13 ноября 2008 года
Kogrom
2.7K / / 02.02.2008
Первое, что приходит в голову - попытаться использовать bat-файл. То есть, завершить программы, предварительно запустив батник, который обновит версию и запустит программу снова.

Ну, или можно специальное приложение вместо батника предусмотреть, которое будет обновлять программу.
341
13 ноября 2008 года
Der Meister
874 / / 21.12.2007
Нормально надо сетевой сервис, у которого можно спросить какие обновления вышли и как их устанавливать. Если вы настаиваете на своей схеме, то без сторонних программ не обойтись. Лучшая из них, на мой вгляд, - установщик Windows.
8.4K
13 ноября 2008 года
z0rch
275 / / 02.09.2008
Согласен с nikitozz, что без дополнительных программ не обойтись. Нужен еще отдельный процесс, который наблюдает за папкой с обновленной программой, и если версия той программы выше чем та что запущена(можно сравнивать с той, что в Program Files установлена) то закрывает программу, обновляет ее и снова включает. Это примерная идея
39K
13 ноября 2008 года
YouROK
12 / / 27.10.2008
Пока что сделал так, программа смотрит есть ли в папке обновление, если есть качает, запускает его и закрывается, это обновление копирует себя на место той программы запускает её и закрываеться.
Обновление проверяется по дате модификации файла.
Если кому надо могу выложить.
8.4K
15 ноября 2008 года
z0rch
275 / / 02.09.2008
1 проблема: если произошла какая нибудь ошибка, то и программа уже закрыта, и обновление не началось
31K
16 ноября 2008 года
dreamer.mas
69 / / 15.11.2008
Куда более элегантным решением будет вынести часть функциональности своей программы в DLL, а при обновлении DLL сама программа сможет найти новые модули в указанном каталоге для обновлений, выгрузить старую DLL и заменить новой.
5
16 ноября 2008 года
hardcase
4.5K / / 09.08.2005
Цитата: dreamer.mas
выгрузить старую DLL и заменить новой.

Не всегда можно обойтись DLL. Гораздо более универсальным способом будет держать в памяти 2 процесса. Один является рабочим процессом, другой - загрузчиком. Проверку обновлений возлагаем на загрузчика. Если в некоторый момент времени загрузчик обнаруживает обновление, он его качает, завершает рабочий процесс (сигнализируя ему или аварийно), накатывает апдейт и запускает его по новой. Кроме того, если задача критичная, загрузчик может выступать как "сторожевой процесс" и перезапускать рабочий процесс в случае его аварийного завершения.

31K
16 ноября 2008 года
dreamer.mas
69 / / 15.11.2008
Цитата: hardcase
Кроме того, если задача критичная, загрузчик может выступать как "сторожевой процесс" и перезапускать рабочий процесс в случае его аварийного завершения.

А еще загрузчик можно использовать для периодического рисования ромашек на рабочем столе :) Как бы, коллега поставил конкретную задачу без надобности всяких "сторожевых процессов". Для одной программы держать в памяти два процесса - роскошь. А вот вынос функционала в DLL - элементарная задача: в самом EXE остается логика программы и средства взаимодействия с пользователем, а вся расчетная часть, которая применяется в программе, выносится в DLL. При обновлении DLL не требуется завершения работы программы, почему этот метод и является более красивым.

А вообще, было бы понятнее, если бы YouROK поведал, что это за программа.

341
16 ноября 2008 года
Der Meister
874 / / 21.12.2007
[QUOTE=dreamer.mas]А вот вынос функционала в DLL - элементарная задача: в самом EXE остается логика программы и средства взаимодействия с пользователем, а вся расчетная часть, которая применяется в программе, выносится в DLL. При обновлении DLL не требуется завершения работы программы, почему этот метод и является более красивым.[/QUOTE]Ну уж, ну уж... Приведи маленький сэмпл того, как легко и просто можно вынести бизнес-логику в библиотеку, а затем подменить её, не завершая приложение.
К "не завершая работы" стремиться, мне кажется, не стоит. Да так никто и не делает. Максимум - отложенное обновление.
31K
16 ноября 2008 года
dreamer.mas
69 / / 15.11.2008
Цитата: Der Meister
Приведи маленький сэмпл того, как легко и просто можно вынести бизнес-логику в библиотеку, а затем подменить её, не завершая приложение.

Всё, что не связано с UI, выносится в DLL, ссылки на соответствующие функции определяются в файле заголовка. При инициализации программы вызывается LoadLibrary, FindResource и LoadResource, задавая адреса функциям в заголовке. При обновлении делается FreeLibrary, копируется новая библиотека, после чего процесс загрузки повторяется.

Цитата: Der Meister
К "не завершая работы" стремиться, мне кажется, не стоит. Да так никто и не делает. Максимум - отложенное обновление.

Ну а что, если тов. YouROK пишет, скажем, антивирус? Критично к обновлениям программы? Да. Чувствительно к перезагрузкам программы? Тоже да. Так что, естественно, решать нужно для конкретного случая, но всё-таки с точки зрения пользователя обновление без необходимости совершения манипуляций со стороны пользователя было бы более приемлемо.

341
16 ноября 2008 года
Der Meister
874 / / 21.12.2007
[QUOTE=dreamer.mas]Всё, что не связано с UI, выносится в DLL, ссылки на соответствующие функции определяются в файле заголовка. При инициализации программы вызывается LoadLibrary, FindResource и LoadResource, задавая адреса функциям в заголовке. При обновлении делается FreeLibrary, копируется новая библиотека, после чего процесс загрузки повторяется.[/QUOTE]Кодом, пожалуйста. Кодом подкрепи. Пусть, к примеру, до обновления программма будет выводить каждые 10 секунд число, на единицу большее, чем предыдущее. А после обновления значение инкремента станет равным двум.
C++
Код:
// Бизнес-логика
class C
{
private:
    int counter;

public:
    C() : counter(0)
    {
    }

    C(int counter) : counter(counter)
    {      
    }

    int Next()
    {
        return counter++;
    }
};
-->
class C
{
   // ...
    int Next()
    {
        int retval = counter;
        counter += 2;
       
        return retval;
    }
}

// Интерфейс
int main()
{
    C c;

    while (true)
    {
        std::cout << c.Next() << std::endl;
        Sleep(10000);
    }
}
Для простоты пусть обновление будет проводиться из дочерней папки .\Update. Оценим, насколько твой подход элегантнее.[QUOTE=dreamer.mas]Ну а что, если тов. YouROK пишет, скажем, антивирус?[/QUOTE][QUOTE=Der Meister]Максимум - отложенное обновление.[/QUOTE]
5
16 ноября 2008 года
hardcase
4.5K / / 09.08.2005
Цитата: dreamer.mas
При обновлении DLL не требуется завершения работы программы, почему этот метод и является более красивым.

Даже для управляемого кода это утверждение выполняется далеко не всегда.

341
16 ноября 2008 года
Der Meister
874 / / 21.12.2007
Да здесь, по-моему, одинаково приятно :)
31K
16 ноября 2008 года
dreamer.mas
69 / / 15.11.2008
Der Meister, если Вы не против, для наглядности интервал между увеличениями переменной уменьшу до 1 секунды. Всё в архиве.

Цитата: hardcase
Даже для управляемого кода это утверждение выполняется далеко не всегда.

Продолжайте, пожалуйста.

5
17 ноября 2008 года
hardcase
4.5K / / 09.08.2005
Цитата: dreamer.mas
Продолжайте, пожалуйста.

Однажды загруженную в контекст исполнения сборку можно отгрузить (и освободить дескриптор ос) только отгрузив домен приложения, который ее использует. Дефолтный (нулевой) домен отгрузить нельзя. Т.е. дефолтный домен придется делать доменом-загрузчиком другого домена - уже того, который будет гонять нужный нам код. Между ними ессно нужно организовывать взаимодействие, в зависимости от сложности системы, можно будет обойтись парой семафоров или же придется настраивать ремотинг.
Над всем этим понятное дело довлеет система безопасности .NET и ОС.

Классический пример: нельзя из управляемого кода моментально остановить поток, находящийся в неуправляемом коде. Поток должен сперва выйти из неуправляемой части, и только потом он будет остановлен CLR. Эта особенность может серьёзно повлиять на остановку рабочего домена приложения и отгрузку его кода.

Вывод: возможность обновления "на лету" нужно закладывать в дизайн сразу, а не прикручивать ее потом.

31K
17 ноября 2008 года
dreamer.mas
69 / / 15.11.2008
Признаться, я мало что понял, поскольку не совсем понимаю, что такое домен. Но в дотнете я успешно тягал функции из библиотек с помощью Remoting и ничего, вроде всё работало нормально.
288
17 ноября 2008 года
nikitozz
1.2K / / 09.03.2007
Если программа уже реализована, то вынос в DLL каких-то ее частей - это потенциальная куча багов.
Да, есть задачи действительно критичные к обновлению, но таких меньшинство. В большинстве же случаев обновляемое приложение завершается и особых неудобств это обычно не вызывает.
341
21 ноября 2008 года
Der Meister
874 / / 21.12.2007
Цитата: dreamer.mas
Der Meister, если Вы не против, для наглядности интервал между увеличениями переменной уменьшу до 1 секунды. Всё в архиве.


Можно было сделать проще, используя полиморфизм. Ну да ладно, суть не в этом.
Пример я выбрал максимально простым неспроста. Твоё решение запросто вылетает с ошибкой доступа к памяти в тот момент, когда исходная библиотека удалена, а новая не помешена на её место, либо ссылки на неё ещё не обновлены, и приложение пытается вызвать из неё функцию. То есть, помимо вызова метода, создающего экземпляр класса Counter, синхронизировать необходимо также каждый из методов класса Counter. И то, этого будет достаточно лишь в том случае, если каждый открытый метод Counter представляет собой законченную логическую операцию.
Кроме того, не ясно, что произойдёт в том случае, если состав инкапсулируемых классом Counter данных изменится. В принципе, вопрос иногда решаем применением полиморфизма (то есть, приложение импортирует интерфейс ICounter, который реализуется закрытым классом Counter1 старой библиотеки; в новой версии есть класс Counter2, также реализующий ICounter, и, кроме этого, имеющий конструктор Counter2(Counter1 & rhs)), но легко можно привести инциденты невозможности и этого шага (просто мы еще не подошли к взаимодействию объектов).
Однако и это - не главное.
Основных же довода два и они взаимосвязаны.
1. При твоём подходе невозможно выделить систему обновления в отдельный логический пакет и обозначить зависимость от него других пакетов, возможна лишь тесная интеграция подверженной обновлению бизес-логики с системой, обеспечивающей это обновление. А это влечёт за собой ряд следствий:
- бессмысленное засерание предметной области совершенно не связанными с ней деталями;
- если мы исчерпывающим образом не определили механизм работы системы обновления на стадии логического дизайна, то прикрутить её впоследствии минимум - нерентабельно, максимум - невозможно.
2. Тебе бы Фаулера почитать... Существует понятие нестабильности пакетов. Пакет тем более нестабилен, чем больше количество импортируемых им классов из других пакетов по отношению к суммарному количеству импортируемых и экспортируемых им классов. Наибольшему изменению подвержены нестабильные пакеты, наименьшему - стабильные. Таким образом, самым нестабильным пакетом становится пользовательский интерфейс, и чем больше мы углубляемся в бизнес-логику, тем она должна становиться стабильнее. Стабильность, в свою очередь, подразумевает следующее: изменение самого стабильного пакета в системе повлечёт за собой изменение большинства остальных пакетов. Иными словами, при подходе "один пакет - один исполняемый модуль" (подходит?) взять и заменить одну дээлэлку не получится - менять придётся сразу большую пачку. И, скорее всего, пользовательский интерфейс будет участвовать где-то в начале титров этой Санта-Барбары. Я это к тому, что подход "меняем бизнес-логику и оставляем интерфейс", скорее всего, неверен в корне.

31K
22 ноября 2008 года
dreamer.mas
69 / / 15.11.2008
Цитата: Der Meister
Пример я выбрал максимально простым неспроста. Твоё решение запросто вылетает с ошибкой доступа к памяти в тот момент, когда исходная библиотека удалена, а новая не помешена на её место, либо ссылки на неё ещё не обновлены, и приложение пытается вызвать из неё функцию.

А мьютекс в counterUpdater я для красоты поставил.

Цитата:
Кроме того, не ясно, что произойдёт в том случае, если состав инкапсулируемых классом Counter данных изменится.

Приведите пример, когда это может произойти при обновлении программы.

Цитата:
При твоём подходе невозможно выделить систему обновления в отдельный логический пакет и обозначить зависимость от него других пакетов

Что Вы понимаете под "отдельным логическим пакетом"?

Цитата:
Тебе бы Фаулера почитать...

Ни буквы не прочту. В предложенном Вами примере у меня всё работает идеально и попробуйте с этим поспорить.

А вообще, согласен с nikitozz.

3
23 ноября 2008 года
Green
4.8K / / 20.01.2000
Код, конечно, отвратительный!
Если пишите якобы на C++, то почему бы не использовать C++ ?

Цитата: dreamer.mas

А мьютекс в counterUpdater я для красоты поставил.


Der Meister прав. Твой мьютекс не отрабатывает все варианты:

 
Код:
ReleaseMutex(lock); <- здесь объект освобожден, а Dll еще не загружна
<---------- А ВОТ ЗДЕСЬ ВСЕ УПАДЕТ -------------->
UpdateDLLProcs();   <- загружается DLL только здесь


Цитата: dreamer.mas

Приведите пример, когда это может произойти при обновлении программы.


Например, новый метод Next должен инкрементировать счетчик на величину равную порядковому номеру созданного экземпляра. Т.е. в программе несколько экземпляров счетчиков:

Код:
c1 = cu.GetInstance();
    c2 = cu.GetInstance();
    c3 = cu.GetInstance();

    while (true)
    {
        cout << c1->Next() << endl;  // Идет с шагом 1
        cout << c2->Next() << endl;  // Идет с шагом 2
        cout << c3->Next() << endl;  // Идет с шагом 3
        Sleep(1000);
    }


Советую разобраться с такими понятиями, как инкапсуляция.
Ты странным образом обновляешь обработчики данных, при этом структура самих данных у тебя всегда одна и та же, а ведь она тоже может (и будет) изменяться.
В данном случае нельзя разрывать данные и обработчики. Посмотри, как устроены COM-объекты.
Твой класс Counter должен был бы выродиться до интерфейса:
 
Код:
class ICounter
{
public:
    virtual int Next() =0;
};

Больше ничего оставлять в основном модуле нельзя. Все остальное должно быть в твоем counter.dll

Цитата: dreamer.mas

Ни буквы не прочту. В предложенном Вами примере у меня всё работает идеально и попробуйте с этим поспорить.


Правильно, ни в коем случае неичего не читай и не учись.
А если у пользователя твоя программа упадет (а она упадет, из-за того, что показано выше), то смело отвечай ему: "у меня всё работает идеально и попробуйте с этим поспорить" :D

31K
23 ноября 2008 года
dreamer.mas
69 / / 15.11.2008
Цитата: Green
Der Meister прав. Твой мьютекс не отрабатывает все варианты:
 
Код:
ReleaseMutex(lock); <- здесь объект освобожден, а Dll еще не загружна
<---------- А ВОТ ЗДЕСЬ ВСЕ УПАДЕТ -------------->
UpdateDLLProcs();   <- загружается DLL только здесь

Хорошо, моя ошибка. Перенесём UpdateDLLProcs в критическую секцию. Всё будет работать, не так ли?

Цитата:
Ты странным образом обновляешь обработчики данных, при этом структура самих данных у тебя всегда одна и та же, а ведь она тоже может (и будет) изменяться.

Для данного случая всё работает. Хотя согласен, что создание классов можно было бы поручить dll, но тем не менее...

341
23 ноября 2008 года
Der Meister
874 / / 21.12.2007
Цитата: dreamer.mas
Для данного случая всё работает. Хотя согласен, что создание классов можно было бы поручить dll, но тем не менее...

Не всё:

Цитата: dreamer.mas
Хорошо, моя ошибка. Перенесём UpdateDLLProcs в критическую секцию. Всё будет работать, не так ли?

Потому что не так. В ту же критическую секцию придётся заключить и Counter::Next(). И каждый из остальных методов класса Counter (сейсас ты синхронизировал пока только "конструктор").
У тебя всё работает потому, что вызов Sleep() в main(), по-видимому, в большенстве тестируемых тобой случаев перекрывает по времени выполнение первой итерации updateWatcher(). У меня же в ста процентах случаев пошагового выполнения программа сыплется с ошибкой 5. Если убрать задержку в main(), крэш получим почти наверняка.

Цитата: dreamer.mas
Что Вы понимаете под "отдельным логическим пакетом"?

Пакет - группа связанных элементов решения. Грубо говоря, это - единица повторного использования набора связанных классов (впрочем, пакет может быть составным, т. е. содержать подпакеты). Пакет может быть выполнен в виде исполняемого модуля, пространства имён, сборки... Может быть вообще никак не обозначен, в конце концов. Главное здесь то, что пакет - способ логически связанные элементы сгруппировать и некоторым образом от остальных элементов системы изолировать. Так вот, при твоей реализации, сказать что "вот тут у нас всё то, что связано конкретно со счётчиком" сказать ну никак не получится - везде придётся тесно взаимодействовать с системой обновления.

63
24 ноября 2008 года
Zorkus
2.6K / / 04.11.2006
Там вот было интересное замечание про два процесса.
Чем не нравится реально это решение?
Не считая конечно замечания что это "роскошь", комментариев по этому поводу особо не увидел.
341
24 ноября 2008 года
Der Meister
874 / / 21.12.2007
Цитата: Zorkus
Там вот было интересное замечание про два процесса.
Чем не нравится реально это решение?
Не считая конечно замечания что это "роскошь", комментариев по этому поводу особо не увидел.


Нормально. Предложенную hardcase схему можно улучшить планированием запуска загрузчика обновлений (используя, например, планировщик задач Windows, если речь идёт об этой ОС).

63
24 ноября 2008 года
Zorkus
2.6K / / 04.11.2006
Цитата: Der Meister
Нормально. Предложенную hardcase схему можно улучшить планированием запуска загрузчика обновлений (используя, например, планировщик задач Windows, если речь идёт об этой ОС).


Если установить подсистему обновления как Windows-service, то можно и собственный шедулинг организовать. Хотя, нужно ли это - решать топикстартеру.

Есть же специальные решения в виде application-wrapper, которые позволяют разнообразные приложения устанавливать как Windows-сервисы с дополнительными примочками (типа перезапуск в случае креша, отслеживание лога на появление подозрительных записей и т.п.).
Сам по специализации знаю такое решение на Java - http://wrapper.tanukisoftware.org/doc/english/download.jsp. Но думаю что и для других платформ такие должны быть.

341
24 ноября 2008 года
Der Meister
874 / / 21.12.2007
Цитата: Zorkus
Если установить подсистему обновления как Windows-service, то можно и собственный шедулинг организовать. Хотя, нужно ли это - решать топикстартеру.

Есть же специальные решения в виде application-wrapper, которые позволяют разнообразные приложения устанавливать как Windows-сервисы с дополнительными примочками (типа перезапуск в случае креша, отслеживание лога на появление подозрительных записей и т.п.).
Сам по специализации знаю такое решение на Java - http://wrapper.tanukisoftware.org/doc/english/download.jsp. Но думаю что и для других платформ такие должны быть.

Действительно, идея выполнить систему обновления в виде службы весьма неплоха. Стандартный планировщик задач - тоже служба (schedule), но твой вариант, кажется, гораздо гибче :)

31K
26 ноября 2008 года
dreamer.mas
69 / / 15.11.2008
Der Meister, да, согласен: код никуда не годный. Наверно, и в самом деле будет удобнее обновлять по расписанию, хотя, опять же, было бы понятнее, если бы автор темы сказал, что у него за программа.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог