Уже запущена копия программы

Здравствуйте, beep, Вы писали:

B>Как предотвратить запуск двух копий приложения
B>в C++ Builder(e). Программа должна работать в W2k.

B> Я уже нашел интересный способ при помощи Mutex(ов)
B> спасибо отвечать не нужно

Re[2]: Как предотвратить запуск двух копий приложения

От: IT linq2db.com
Дата: 05.05.03 01:59
Оценка:

Здравствуйте, beep, Вы писали:

B>Как предотвратить запуск двух копий приложения
B>в C++ Builder(e). Программа должна работать в W2k.

B> Я уже нашел интересный способ при помощи Mutex(ов)
B> спасибо отвечать не нужно

Ну так поделись интересным способом с коллегами

Если нам не помогут, то мы тоже никого не пощадим.
Re[3]: Как предотвратить запуск двух копий приложения

От: VVP 67524421
Дата: 05.05.03 06:14
Оценка:

Здравствуйте, IT, Вы писали:

ПРОГРАММА УЖЕ ЗАПУЩЕНА,НО НЕ ВЫХОДИТ/РЕШЕНИЕ ПРОБЛЕМЫ



IT>Ну так поделись интересным способом с коллегами
Чего делиться-то? Способ стандартный, описанный и рекомендованный борландом, даже в факе борландовском есть.
Пример почти списан у борланда

program MyProg; uses Windows, Forms, Form1, . ; begin // пробуем создать мъютекс CreateMutex(nil, false, ‘MyProg’); // если не удалось — есть другой экземпляр if GetLastError = ERROR_ALREADY_EXISTS then begin Halt(0); end; Application.Initialize; . Application.CreateForm(TForm1, Form1); Application.Run; end;

Как видно, обычная Win32`ая проверка на вшивость
В точности по рекомендации MS: создать мъютекс, проверить на ERROR_ALREADY_EXISTS, если ошибка возникла, то начинаем что-то делать со старым экземпляром и прерываем исполнение нового.

Никогда не бойся браться делать то, что делать не умеешь. Помни, ковчег был построен любителем. Профессионалы построили Титаник.

Re[4]: Как предотвратить запуск двух копий приложения

От: sercher
Дата: 05.05.03 06:23
Оценка:

Только при аварийном (или неправильном) завершении одного экземпляра, следующий уже не запуститься, так как объект ядра не удалиться.

Re[5]: Как предотвратить запуск двух копий приложения

От: VVP 67524421
Дата: 05.05.03 06:25
Оценка:

Здравствуйте, sercher, Вы писали:

S>Только при аварийном (или неправильном) завершении одного экземпляра, следующий уже не запуститься, так как объект ядра не удалиться.

ЧТО ДЕЛАТЬ ЕСЛИ НЕ СКАЧИВАЕТСЯ STEAM


Кто бы спорил
Конечно же надо предусмотреть CloseHandle(MyBestProgMutex).

Никогда не бойся браться делать то, что делать не умеешь. Помни, ковчег был построен любителем. Профессионалы построили Титаник.

Re[6]: Как предотвратить запуск двух копий приложения

От: mrhru
Дата: 05.05.03 06:41
Оценка: +1

Здравствуйте, VVP, Вы писали:

VVP>Здравствуйте, sercher, Вы писали:

S>>Только при аварийном (или неправильном) завершении одного экземпляра, следующий уже не запуститься, так как объект ядра не удалиться.
VVP>Кто бы спорил
VVP>Конечно же надо предусмотреть CloseHandle(MyBestProgMutex).

Если я всё правильно напутал.

1) WinAPI Help.
The system closes the handle automatically when the process terminates.
The mutex object is destroyed when its last handle has been closed.

2) Создавать Mutex надо с флагом bInitialOwner = true, иначе функция CreateMutex вернёт handle на уже открытый.

Re[7]: Как предотвратить запуск двух копий приложения

От: ArtDenis
Дата: 05.05.03 12:36
Оценка:

Здравствуйте, mrhru, Вы писали:

M>1) WinAPI Help.
M>The system closes the handle automatically when the process terminates.
M>The mutex object is destroyed when its last handle has been closed.
Мечты, мечты. Бывает, что при завершении зависшего приложения из TaskManager’a хенделы не закрываются. Кроме того, приложение может рухнуть само так, что система не закроет выделенные ресурсы. Выход из этой проблемы — это писать не падающие и не зависающие приложения.

M>2) Создавать Mutex надо с флагом bInitialOwner = true, иначе функция CreateMutex вернёт handle на уже открытый.
bInitialOwner используется для других целей в данном случае это не принципиально.

Лично я в Бллдере использую такой класс:

class APP_EXISTER < HANDLE event; bool exists; public: APP_EXISTER(const char *name) < event = OpenEvent(EVENT_MODIFY_STATE, false, name); exists = (event != INVALID_HANDLE_VALUE) (event != NULL); if (!exists) event = CreateEvent(NULL, true, false, name); > ~APP_EXISTER() < if ((event != INVALID_HANDLE_VALUE) (event != NULL)) CloseHandle(event); > bool is_exists() < return exists; > >;

Используется он так:

APP_EXISTER app_exst(«APP_NAME»); // объявляется глобальная переменная этого класса

Дальше перед Application->Run(); смотрим

if ( app_exst.is_exists() ) < // другая копия уже существует, завершаеи приложение >

Удобство класса в том, что при завершении приложения о автоматом сделает CloseHandle(event);

Re[2]: Как предотвратить запуск двух копий приложения

От: SmaLL75 http://smallweb.narod.ru
Дата: 06.05.03 05:26
Оценка: -1

Здравствуйте, beep, Вы писали:

B> Я уже нашел интересный способ при помощи Mutex(ов)
B> спасибо отвечать не нужно

Может он и интересный, но я обычно пульзуюсь этим:

var hwndPrev: HWND; begin Application.Initialize; hwndPrev:= FindWindow(‘TSendMainForm’, nil); if hwndPrev <> 0 then begin PostMessage(hwndPrev, WM_USER + 2, 0, 0);// это сообщение ловит TSendMainForm и отображает себя Application.Terminate; end else begin Application.Title := ‘Послать’; Application.ShowMainForm := False; Application.CreateForm(TSendMainForm, SendMainForm); ShowWindow(Application.Handle, SW_HIDE); Application.Run; end;
Что ни делается, всЁ к лучшему
Re[3]: Как предотвратить запуск двух копий приложения

Читайте также:
Прочтите документ почему данную программу можно считать националистической
От: ArtDenis
Дата: 06.05.03 06:39
Оценка:

Здравствуйте, SmaLL75, Вы писали:

SLL>
SLL>var SLL> hwndPrev: HWND; SLL>begin SLL> Application.Initialize; SLL> hwndPrev:= FindWindow(‘TSendMainForm’, nil); SLL> if hwndPrev <> 0 then SLL> begin SLL> PostMessage(hwndPrev, WM_USER + 2, 0, 0);// это сообщение ловит TSendMainForm и отображает себя SLL> Application.Terminate; SLL> end SLL> else SLL> begin SLL> Application.Title := ‘Послать’; SLL> Application.ShowMainForm := False; SLL> Application.CreateForm(TSendMainForm, SendMainForm); SLL> ShowWindow(Application.Handle, SW_HIDE); SLL> Application.Run; SLL> end; SLL>

А как всё это работает из под среды? В дизайнере форм Design-Time форма имеет то-же самое имя что и запускаемая. Или я не прав?

Re[4]: Как предотвратить запуск двух копий приложения

От: SmaLL75 http://smallweb.narod.ru
Дата: 06.05.03 07:06
Оценка:

Здравствуйте, ArtDenis, Вы писали:

AD>А как всё это работает из под среды? В дизайнере форм Design-Time форма имеет то-же самое имя что и запускаемая. Или я не прав?

Прав. Если запущена среда и отктыта эта форма, то программа не запустится.
Я использую директивы условной компиляции. На время разработки отключаю запрет запуска, а в релизе включаю. Зато при падении проиложения никаких хвостов не остаЁтся, если не считать иконки в трее, которая пропадает при первой же перерисовки трея.

Что ни делается, всЁ к лучшему
Re[5]: Как предотвратить запуск двух копий приложения

От: sercher
Дата: 06.05.03 07:29
Оценка:

По моему проще всего искать окно с таким же Caption. Единственный недостаток — все версии должны иметь один Caption на главной форме.

Re[3]: Как предотвратить запуск двух копий приложения

От: VVP 67524421
Дата: 06.05.03 07:33
Оценка:

Здравствуйте, SmaLL75, Вы писали:

SLL>Может он и интересный, но я обычно пульзуюсь этим:

SLL> hwndPrev:= FindWindow(‘TSendMainForm’, nil);

Плохой способ.
Ну для примера рассмотрим ситуацию, когда у тебя за душой несколько SDI проектов, реализованных с помощью одной структуры классов, соответственно главная форма у каждого проекта одного класса: «TBusinessApp». Запустив на исполнение один проект, ты никогда в жизни не запустишь другой.
Читайте Рихтера (издание 3, глава 3), там русским по белому сказано, что использование FindWindow для этих целей — нехороший способ, вместо этого надо использовать мъютексы. Если уж классики на Вас не произведут впечатление, то других аргументов у меня не осталось. Один аргумент про FAQ от Borland`а я уже приводил, другой про описание WinMain из Platform SDK (MSDN) тоже.

Никогда не бойся браться делать то, что делать не умеешь. Помни, ковчег был построен любителем. Профессионалы построили Титаник.

Re[4]: Как предотвратить запуск двух копий приложения

От: SmaLL75 http://smallweb.narod.ru
Дата: 06.05.03 13:43
Оценка:

VVP>Читайте Рихтера (издание 3, глава 3), там русским по белому сказано, что использование FindWindow для этих целей — нехороший способ, вместо этого надо использовать мъютексы.

Знаю только такого композитора.

Что ни делается, всЁ к лучшему
Re[5]: Как предотвратить запуск двух копий приложения

От: VVP 67524421
Дата: 06.05.03 13:51
Оценка:

Здравствуйте, SmaLL75, Вы писали:

VVP>Читайте Рихтера.
SLL>Знаю только такого композитора.
Ага, а Дельфи это город в Греции, а Оракл это одно из чудес света, в этом городе инкапсулированное.

Никогда не бойся браться делать то, что делать не умеешь. Помни, ковчег был построен любителем. Профессионалы построили Титаник.

Re[6]: Как предотвратить запуск двух копий приложения

От: AlexandrN
Дата: 06.05.03 13:55
Оценка:

hMap = CreateFileMapping( (HANDLE)0xFFFFFFFF, NULL, PAGE_READONLY, 0, 1, AppID ); if ( hMap != NULL GetLastError() == ERROR_ALREADY_EXISTS ) MessageBox( 0, «Запуск второй копии программы недопустим.», AppID, MB_OK | MB_ICONSTOP | MB_TOPMOST); else < // Запускаем программу >
С уважением.
AlexandrN
Re[7]: Как предотвратить запуск двух копий приложения

От: AlexandrN
Дата: 06.05.03 14:00
Оценка:

Поправки(чёто савсем забыл):

const char *AppID = «Моя программа»; HANDLE hMap; hMap = CreateFileMapping( (HANDLE)0xFFFFFFFF, NULL, PAGE_READONLY, 0, 1, AppID ); if ( hMap != NULL GetLastError() == ERROR_ALREADY_EXISTS ) MessageBox( 0, «Запуск второй копии программы недопустим.», AppID, MB_OK | MB_ICONSTOP | MB_TOPMOST); else < // Запускаем программу > CloseHandle(hMap); hMap = NULL;

Источник: www.rsdn.org

Уже запущена копия программы

Издано: 2003, BHV
Твердый переплет, 560 стр..

Способы обнаружения копии уже загруженной программы

(статья была опубликована в журнале «Программист»)

В третьем номере журнала «Программист» за 2002 год была опубликована статья Андрея Нефедова «Запрет запуска копии приложения под Windows». Перечисленные в ней способы обнаружения уже запущенной копии программы сводились к одному — созданию какого-либо глобального именного объекта и последующей проверки его наличия. Основной недостаток такого подхода — отсутствие гарантий уникальности глобальных имен. Одно и то же имя могут использовать две различные программы, что приведет к очевидному конфликту — вторая не станет запускаться, если активная первая.

Читайте также:
Какую программу установить чтобы знать где находится ребенок

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

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

Но при ближайшем рассмотрении такой недостаток оборачивается достоинством — пользователь получает возможность одновременной работы с различными версиями одного и того же приложениями, установленными в «свои» каталоги!

Получить список процессов легче всего средствами TOOLHELP32. Для этого сначала необходимо вызовом CreateTollhelp32snapshot снять «слепок» состояния процессоров, а затем передать возращенный ею дескриптор функциям Process32First и Process32Next. Каждый процесс, в свою очередь, ассоциирован с одним или несколькими модулями, список которых можно получить с помощью функций Module32First и Module32Next, предварительно сделав «слепок» состояния владеющего ими процесса вызовом CreateTollhelp32snapshot.

Ниже приведен исходный текст программы, выводящий на экран полные имена файлов, загруженных или исполняющихся в данный момент. Имя же самой программы передается ей в нулевом аргументе командной строки. Программа прекрасно работает как под Windows 9x, так и под Windows NT2000.

#include #include #include // заголовочный файл библиотеки TOOLHELP32 // функция выводит список модулей, ассоцированных // с данным процессом void GetModuleList(DWORD th32ProcessID) < HANDLE h; MODULEENTRY32 mdl; // создание «слепка» состояния всех // модулей процесса th32ProcessID h=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, th32ProcessID); // для инициализации структуры MODULEENTRY32 // необходимо указать ее размер mdl.dwSize=sizeof(MODULEENTRY32); // получение сведений о первом модуле в списке Module32First(h, while(1) < // в поле szExePath содержится полное имя // файла-модуля printf(«tszExePatht-t%sn»,mdl.szExePath); // получение сведений о всех остальных модулях // или выход, если конец if (!Module32Next(h, >// уничтожение «слепка» CloseHandle(h); > main() < HANDLE h; PROCESSENTRY32 pe; // создание «слепка» состояния всех процессов // второй аргумент при «слепке» состояния процессов // игнорируется и может принимать какие угодно // значения h=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,NULL); // для инициализации структуры PROCESSENTRY32 // необходимо указать ее размер pe.dwSize=sizeof(PROCESSENTRY32); // получение сведений о первом процессе в списке Process32First(h, while(1) < // в поле szExePath содержится имя исполняемого // файла, ассоциированного с процессом, без пути printf(«szExeFilet-t%sn»,pe.szExeFile); // в поле th32ProcessID содержится идентификатор // процесса, с помощью которого можно получить // список модулей данного процесса. // Это необходимо для выяснения полного имени // исполняемого файла GetModuleList(pe.th32ProcessID); // получение сведений о следующем процессе // или выход, если конец if (!Process32Next(h, >return 0; >

Листинг 8 Демонстрация отслеживания уже запущенной копии программы путем просмотра списка процессов средствами TOOLHELP

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

Демонстрационный пример реализации приведен ниже.

#include #include #include main() < char buff[2]; HANDLE h; // Создание временного файла h=CreateFile(«my»,GENERIC_WRITE, NULL,NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL); // если открытие прошло успешно – нормальная работа if (h!=INVALID_HANDLE_VALUE) printf(«Hello, Sailor!n»); else // если возникла ошибка совместного доступа, // следовательно, приложение уже было запущено if (GetLastError()==ERROR_SHARING_VIOLATION) < printf(«Нельзя запускать более» «одной копии приложения!n»); return; >// ожидание нажатие на fgets( >

Листинг 9 Демонстрация отслеживания уже запущенной копии программы путем блокирования совместного доступа к дисковому файлу

Аккуратно написанная программа должна не просто завершать свою работу, обнаружив уже загруженную копию, но и переключать эту копию на передний план, — так работают практически все «фирменные» приложения. Для осуществления такой операции необходимо знать дескриптор главного окна программы.

Выяснить это поможет широковещательная рассылка сообщений. Передав функции SendMessage в качестве первого аргумента константу HWND_BROADCAST, можно заставить ее посылать сообщения всем top-level окнам. В сообщении следует указать уникальный код, позволяющий безошибочно идентифицировать данное приложение (см. врезку «пути достижения уникальности»).

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

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

Если требуется ограничить количество одновременно работающих копий одного и того же приложения, можно воспользоваться динамической ветвью реестра HKEY_DYN_DATA, создав в «своем» разделе специальную переменную увеличивающуюся на единицу при очередном запуске и уменьшающуюся при выходе из приложения. Почему необходимо использовать именно динамическую ветвь? Дело в том, что если работа программы будет аварийно завершена (например, погаснет свет или произойдет критическая ошибка), счетчик запущенных приложений, расположенный в статичной ветке реестра, окажется не обнулен! Напротив, HLEY_DUN_DATA хранится в оперативной памяти и очищается при каждой перезагрузке операционной системы. По этой же причине, никогда не следует хранить счетчик запущенных приложений во временном файле! (Разве, на виртуальном диске)

Читайте также:
Установка программ через wine

Способов обнаружения ранее запушенных копий программ существует очень много — всех не перечислишь! Поэтому, не следует «зацикливаться» на одном FindWindow – подходите к решению каждой задачи творчески. Экспериментируйте, ищите собственные методы! Уверяю, они есть. На последок еще один довольно неожиданный способ, основанный на буфере обмена.

Если приложение регистрирует свой собственный формат данных (как часто и бывает), передавая его название функции RegisterClipboardFormat, это может служить отличным индикатором наличия уже запущенной копии приложения!

Причем, после выхода из приложения зарегистрированный формат не удаляется и не существует функций API, удаляющих его «в ручную». Это обстоятельство можно использовать для создания программ, рассчитанных всего лишь на один запуск на каждый сеанс работы с Windows. Использование динамической ветви реестра дает не худший результат за одним небольшим исключением — манипуляции с реестром элементарно отслеживают даже неопытные пользователи, вооруженные мониторами реестра, и при желании они смогут легко заставить приложение запуститься повторно, удалив из реестра соответствующую запись.

Замечание: кстати, ограничение «однократный запуск на весь сеанс работы с Windows» очень хорошо подходит для Shareware-программ. Такая защита чрезвычайно проста в реализации и, в то же время, не может быть обманута рядовым пользователем. Конечно, профессиональных взломщиков она не остановит, но в большинстве случаев этого и не требуется!

Пути достижения уникальности: прежде чем использовать способы, предложенные Нефедовым в его статье, необходимо научиться формировать уникальные имена, гарантированно не используемые никакими другими приложениями.

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

Второй способ заключается в использовании генератора случайных чисел, с помощью которого формируется уникальное имя до компиляции приложения. В среду разработки Microsoft Visual Studio входит удобная и компактная утилита UUIDGEN, генерирующая 128 битный уникальный идентификатор. Вообще-то она предназначается для создания неконфликтных идентификаторов интерфейсов OLE и ActiveX объектов, но ничуть не хуже подходит и для нашего случая.

Источник: citforum.ru

Уже запущена копия программы

Это надо делать не c самим окном, а с окном приложения,
т.е. wnd := HWND(GetWindowLong(wnd, GWL_HWNDPARENT)).

Ну, а окно главной формы всегда существует.
Если, конечно, приложение не бесформенное 😉

var
ObjName: PChar;
Handle: THandle;
AppWnd: HWnd;
IsTerm: boolean;
const
UnicName = «Starvara»;
Duplicate = «duplicate»;

Надо перед этим вызвать AttachThreadInput, тогда обязательно сработает.

novice__man
Установи пакет компонентов JVCL, там есть компонент который отлично справляется с твоей задачей. Проверено.

Спасибо за предложение. Но у меня все работает, спасибо интернету :), бездна информации.

А насчет дополнительных компонентов, то мне не очень нравится их использовать в своих проектах, но как справочная информация и пример реализации (если конечно они с исходниками) они мне подходят.

novice__man
Установи пакет компонентов JVCL, там есть компонент который отлично справляется с твоей задачей. Проверено.

Спасибо за предложение. Но у меня все работает, спасибо интернету :), бездна информации.

А насчет дополнительных компонентов, то мне не очень нравится их использовать в своих проектах, но как справочная информация и пример реализации (если конечно они с исходниками) они мне подходят.

const
StartEvent: string= «MySuperPuperProgramm»;

procedure ActivateOldInstance;
var
FoundWindow, FoundPopup : THandle;
begin;
try;
FoundWindow:=FindWindow(nil,PChar(AppTitle));
if FoundWindow<>0 then begin;
FoundPopup:=GetLastActivePopup(FoundWindow);
if IsIconic(FoundWindow) then ShowWindow(FoundWindow,SW_RESTORE);
BringWindowToTop(FoundWindow);
SetForegroundWindow(FoundWindow);
if FoundPopup<>0 then begin;
if IsIconic(FoundPopup) then ShowWindow(FoundPopup,SW_RESTORE);
BringWindowToTop(FoundPopup);
SetForegroundWindow(FoundPopup);
end;
end;
except end;
end;

PFirstCopyInfo = ^TFirstCopyInfo;
TFirstCopyInfo = record
Window: HWND
end;

var
G_HFirstCopyMap: Cardinal = 0;

function AnotherCopyExists: Boolean;
begin
G_HFirstCopyMap :=
CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE or SEC_COMMIT,
0, G_FirstCopyMapSize, G_SFirstCopyMapName);
Result := GetLastError = ERROR_ALREADY_EXISTS;
if G_HFirstCopyMap = 0 then
Exit;
G_LPFirstCopyInfo :=
MapViewOfFile(G_HFirstCopyMap, FILE_MAP_WRITE, 0, 0, G_FirstCopyMapSize);
G_ActivateAnotherCopyMsg := RegisterWindowMessage(G_ActivateAnotherCopyMsgName)
end;

procedure CloseFirstCopyInfo;
begin
if G_LPFirstCopyInfo <> nil then
begin
UnmapViewOfFile(G_LPFirstCopyInfo);
G_LPFirstCopyInfo := nil
end;
if G_HFirstCopyMap <> 0 then
begin
CloseHandle(G_HFirstCopyMap);
G_HFirstCopyMap := 0
end
end;

Две глобальные переменные:

G_LPFirstCopyInfo: PFirstCopyInfo = nil;
G_ActivateAnotherCopyMsg: Cardinal = 0;

Источник: delphimaster.net

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru