adsl club

Справочник

Форум

Программы

Фильмы

Ресурсы

Файлообмен

Хостинг

Ростелеком
Недопущение запуска более одной копии приложения
На страницу 1 2
Ответить на тему    Форум АДСЛ КлубаЦИФРОВОЙ ФЛЕЙМ :)ПРОГРАММИРОВАНИЕ
Автор Сообщение
AlexRock
Гуру
СообщениеДобавлено: Пн 31-03-08 : 18-05    Заголовок сообщения: Недопущение запуска более одной копии приложения Ответить с цитатой

Среда: Builder
Язык: C++

Я запускаю из своей оболочки разные программы (жму кнопку в оболочке и это событие обрабатывается функцией CreateProcess).
Нужно не позволить пользователю запускать больше одной копии приложения. Варианты со всякими Mutex не желательны, ибо сильно заумно (хотя, на худой конец, и этот вариант подойдёт). Имена процессов известны.

Я нашёл такую вещь: ( http://blogs.gotdotnet.ru/personal/gaidar/CommentView.aspx?guid=bbafb327-38d9-4a07-ab2e-8c5a504adf0a )

Код:
static bool CheckProcess()
    {
        int count = 0;
        Process[] proc = Process.GetProcesses();
        for (int i = 0; i < proc.Length; i++)     // перебор запущенных процессов
        {
            if (proc[i].ProcessName == "MyApp.exe")
            count++;
        }
        if (count > 1) return true; // здесь я думаю заменить на
// if (count > 1)
// {
//      закрыть_процесс();
//      return true;
// }                                             
 
        return false;
    }


Какая функция на самом деле закрывает процесс (вместо написанной мной фиктивной закрыть_процесс()), если известно имя процесса? Причём закрываться процесс должен из моей оболочки (в её коде это должно быть реализовано), поэтому мне и надо знасть синтаксис написания функции закрытия процесса по известному имени этого процесса.

Весь код запуска процесса, проверки на единичность запущенного процесса и его убийство, если его запущено более одного раза:

Код:
void __fastcall TForm1::Button3Click(TObject *Sender)
{
    if(CheckProcess()) return;
   
    // если процесс ещё не запущен, то позволяем запустить его
    STARTUPINFO sinfo;
    PROCESS_INFORMATION pinfo;
    memset(&pinfo, 0, sizeof(pinfo));
    memset(&sinfo, 0, sizeof(sinfo));
    sinfo.cb = sizeof(sinfo);

    CreateProcess(NULL, "MyApp.exe",
        NULL, NULL, false, 0, NULL, NULL, &sinfo, &pinfo);
}
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
dlnsk
Гуру
СообщениеДобавлено: Пн 31-03-08 : 18-47    Заголовок сообщения: Ответить с цитатой

А может просто не запускать процесс если он уже запущен? Если ты их все-равно из своей оболочки запускаешь...
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение Посетить сайт автора  
Vlad
Гуру
Предупреждений : 4
СообщениеДобавлено: Пн 31-03-08 : 22-08    Заголовок сообщения: Ответить с цитатой

Цитата:
Какая функция на самом деле закрывает процесс (вместо написанной мной фиктивной закрыть_процесс()), если известно имя процесса?

Посмотри в диспетчере задач,у тебя минимум 3-5 процессов svchost.exe.
Иными словами убивать процесс по имени неверно.Нужно знать pid нужного процесса,через него получить хендл [те открыть процесс с флагом PROCESS_TERMINATE] и убить его через TerminateProcess
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение   Номер ICQ
AlexRock
Гуру
СообщениеДобавлено: Вт 1-04-08 : 01-59    Заголовок сообщения: Ответить с цитатой

dlnsk писал(а):
А может просто не запускать процесс если он уже запущен? Если ты их все-равно из своей оболочки запускаешь...

Я хочу от защититься от юзера, который любит побаловаться, понажимать на кнопочку запуска раз сто. Как-то так.
Vlad писал(а):
Цитата:Какая функция на самом деле закрывает процесс (вместо написанной мной фиктивной закрыть_процесс()), если известно имя процесса?


Посмотри в диспетчере задач,у тебя минимум 3-5 процессов svchost.exe.

Иными словами убивать процесс по имени неверно.Нужно знать pid нужного процесса,через него получить хендл [те открыть процесс с флагом PROCESS_TERMINATE] и убить его через TerminateProcess

А если изменить код так:
Код:
static bool CheckProcess()
    {
        int count = 0;
        Process[] proc = Process.GetProcesses();
        for (int i = 0; i < proc.Length; i++)     // перебор запущенных процессов
        {
            if (proc[i].ProcessName == "MyApp.exe") return true; // если нашёл хотя бы один с нужным именем, то возвращает истину
        }
        return false;
    }

///////////////////////

void __fastcall TForm1::Button3Click(TObject *Sender)
{
    if(CheckProcess()) return; // если функция вернула истину, то значит, что один
                                          // искомый процесс уже есть, тогда не даём кнопке Button3
                                          // запустить ещё такой же процесс
   
    // если процесс ещё не запущен, то позволяем запустить его
    STARTUPINFO sinfo;
    PROCESS_INFORMATION pinfo;
    memset(&pinfo, 0, sizeof(pinfo));
    memset(&sinfo, 0, sizeof(sinfo));
    sinfo.cb = sizeof(sinfo);

    CreateProcess(NULL, "MyApp.exe",
        NULL, NULL, false, 0, NULL, NULL, &sinfo, &pinfo);
}


Думаю, что это проще (не надо ничего убивать - просто не даю запустить второй раз) и должно сработать. Ктознибудь видит что-нибудь неправильное?

Vlad, а TerminateProcess - это функция, ведь. Какой у неё полный синтаксис? Я в справке нашёл только

1.
Returns true.

BOOL __fastcall TerminateExtension(int dwFlags);

Description

The HTTP server calls TerminateExtension when it wants to shut down the ISAPI application. TerminateExtension always returns true, allowing the server to shut down.

2.
Header File

stdlib.h

Category

Process Control Routines

Prototype

void abort(void);

Description

Abnormally terminates a program.

abort causes an abnormal program termination by calling raise(SIGABRT). If there is no signal handler for SIGABRT, then abort writes a termination message (Abnormal program termination) on stderr, then aborts the program by a call to _exit with exit code 3.

Return Value

abort returns the exit code 3 to the parent process or to the operating system command processor.

3.
Ends application execution.

void __fastcall Terminate(void);

Description

Call Terminate to end the application programmatically. By calling Terminate rather than freeing the application object, you allow the application to shut down in an orderly fashion.

Terminate calls the Windows API PostQuitMessage function to perform an orderly shutdown of the application. Terminate is not immediate.

Terminate is called automatically on a WM_QUIT message and when the main form closes.

----
Ничего насчёт "убить другой конкретный процесс из своего приложения" нету.
Последний раз редактировалось: AlexRock (Вт 1-04-08 : 02-11), всего редактировалось 1 раз
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
dlnsk
Гуру
СообщениеДобавлено: Вт 1-04-08 : 02-10    Заголовок сообщения: Ответить с цитатой

AlexRock писал(а):
просто не даю запустить второй раз

Дык я вроде это и предлагал... Very Happy
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение Посетить сайт автора  
AlexRock
Гуру
СообщениеДобавлено: Вт 1-04-08 : 02-13    Заголовок сообщения: Ответить с цитатой

dlnsk писал(а):
AlexRock писал(а):просто не даю запустить второй раз


Дык я вроде это и предлагал...

Я думал, что вы предлагаете мне не жать на кнопку запуска, а не в коде не давать. Вобщем попробую завтра, а то спать охота - ничё не соображаю...
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
Vlad
Гуру
Предупреждений : 4
СообщениеДобавлено: Вт 1-04-08 : 22-08    Заголовок сообщения: Ответить с цитатой

Поверь мне и сделай детект через MUTEX.
Там нет ничего заумного,все просто:
если именованный mutex существует,значит одна копия уже запущена.действия по желанию.Нет такого mutex'a? Создаем и работаем дальше.

А то,что ты нагородил в коде выше,как я понял,превосходит твой текущий уровень [имеется ввиду отладка и ньюансы о которых ты похоже даже не подозреваешь. напр. что если твою программу переименуют в 123.exe? ]
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение   Номер ICQ
AlexRock
Гуру
СообщениеДобавлено: Ср 2-04-08 : 01-37    Заголовок сообщения: Ответить с цитатой

Vlad писал(а):
А то,что ты нагородил в коде выше,как я понял,превосходит твой текущий уровень [имеется ввиду отладка и ньюансы о которых ты похоже даже не подозреваешь. напр. что если твою программу переименуют в 123.exe? ]

Отладка? Я ещё не потестил этот свой вариант, но, надеюсь, проканает. А программы (оболочку и остальные) никто переименовывать не должен. Это моё недопущение запуска копии - это не какая-то супер защита от "пиратства", а просто, от баловства. Если юзер сильно хочет побаловаться, то пусть переименовывает... пусть хоть свой комп в окно выбрасывает. Я буду спокоен, что от первичного соблазна его избавил.
Я просто не в курсе, что это за Мутекс и зачем он нужен. Разве тупой перебор процессов - это недостаточно. Вобщем, попробую и отпишусь, как получилось. Сегодня опять руки не дошли.
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
AlexRock
Гуру
СообщениеДобавлено: Ср 2-04-08 : 01-48    Заголовок сообщения: Ответить с цитатой

Вобщем, выдаёт такой список ошибок

*[C++ Error] Unit1.cpp(67): E2451 Undefined symbol 'Process'
*[C++ Error] Unit1.cpp(67): E2188 Expression syntax
*[C++ Error] Unit1.cpp(69): E2451 Undefined symbol 'proc'

в коде (* - позиции курсора)

66 Process[*]* proc = Process.GetProcesses();
67 // перебор запущенных процессов
68 for (int i = 0; i < proc*.Length; i++)
69 {
70 // если нашёл хотя бы один с нужным именем, то выходим из
71 // функции, не дав запустить этот процесс ещё раз
72 if (proc[i].ProcessName == "MyApp.exe") return;
73 }
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
AlexRock
Гуру
СообщениеДобавлено: Ср 2-04-08 : 20-26    Заголовок сообщения: Ответить с цитатой

Vlad писал(а):
Поверь мне и сделай детект через MUTEX.

Там нет ничего заумного,все просто:

если именованный mutex существует,значит одна копия уже запущена.действия по желанию.Нет такого mutex'a? Создаем и работаем дальше.

Я ничего про это не знаю. Мне бы готовый код, если можно... Или, хотя бы, пояснения.

А насчёт верхнего: я не понимаю, почему компилятор не понимает массив Process? Может, он не знает, что такое proc? Тут, похоже, по-любому какая-то библиотека подключается (директивой #include, например), иначе компилятор не понимает ничего.
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
Vicor
Начинающий
СообщениеДобавлено: Ср 2-04-08 : 22-46    Заголовок сообщения: Ответить с цитатой

Код:

WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
   HANDLE h = CreateMutex(NULL, FALSE, "MySuperPuperApplication");
   if(GetLastError() == ERROR_ALREADY_EXISTS)
   {
      // Приложение уже запущено
      return 0;
   }
   // Приложение запущено в первый раз
   // ...

   CloseHandle(h);
   return 0;
}
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
AlexRock
Гуру
СообщениеДобавлено: Чт 3-04-08 : 02-52    Заголовок сообщения: Ответить с цитатой

Vicor
Это определение функции, а мне бы пример использования: что в параметрах WinMain задать?

Мне надо два приложения проверять на наличие копии. Вот так если сделать (пару строк добавил)

Код:
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
   HANDLE h = CreateMutex(NULL, FALSE, "App1.exe");
   HANDLE a = CreateMutex(NULL, FALSE, "App2.exe"); // это я добавил

   if(GetLastError() == ERROR_ALREADY_EXISTS)
   {
      // Приложение уже запущено
      return 0;
   }
   // Приложение запущено в первый раз
   // ...

   CloseHandle(h);
   CloseHandle(a); // это я добавил
   return 0;
}


то нормально будет?

Ещё вопрос. Мне надо в двух разных функциях (обработчики событий нажатия на кнопку - запуск соответствующего приложения) эту WinMain вызвать. Я думаю, что для соответствующего обработчика надо либо свой вариант WinMain писать (чтобы не объявлять два HANDLE), либо написать так, как я (один вариант WinMain на все случаи) и вызвать в каждом обработчике эту WinMain. Я прав? Тогда мне нужны параметры для передачи в WinMain - для примера, а то я не понимаю, что значат HINSTANCE hInstance, HINSTANCE, LPSTR, int? Они в этой функции нигде не используются.
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
Aprelle
Гуру
СообщениеДобавлено: Чт 3-04-08 : 11-33    Заголовок сообщения: Ответить с цитатой

Все что тебе нужно, это

Код:

CreateMutex(NULL, FALSE, "MySuperPuperApplication");
if(GetLastError() == ERROR_ALREADY_EXISTS)
   {
      // Приложение уже запущено
      return 0;
   }
...


Все, больше никакими винмэйнами, App1.exe и App2.exe не увлекайся.
Лучше возьми 10 толстых справочников по си++, засядь в интернет и потрать с пользой два дня на то, чтобы разобраться с первой строчкой этого кода )))
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
dlnsk
Гуру
СообщениеДобавлено: Чт 3-04-08 : 13-32    Заголовок сообщения: Ответить с цитатой

AlexRock писал(а):
что в параметрах WinMain задать?

Эээ... тяжелый случай... Smile

Aprelle
Вообще-то мьютекс должна создавать та прога, которую он запускает из оболочки и еще она должна его удалять...
Если создавать мьютекс в оболочке, то это не даст никакого выйгрыша ибо нужно будет отслеживать завершение "дочерней" программы, а если забыть его удалить, то потом после закрытия "дочерней" программы ее уже вообще невозомжно будет запустить... Wink

AlexRock
http://www.firststeps.ru/mfc/winapi/r.php?118
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение Посетить сайт автора  
Aprelle
Гуру
СообщениеДобавлено: Чт 3-04-08 : 16-06    Заголовок сообщения: Ответить с цитатой

dlnsk

>Вообще-то мьютекс должна создавать та прога, которую он запускает из оболочки

ну я это и подразумевал

>и еще она должна его удалять...

а это хорошее примечание !-)
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
AlexRock
Гуру
СообщениеДобавлено: Чт 3-04-08 : 19-44    Заголовок сообщения: Ответить с цитатой

dlnsk писал(а):
Вообще-то мьютекс должна создавать та прога, которую он запускает из оболочки и еще она должна его удалять...

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

Ладно, в "Первых шагах" поковыряюсь. Ещё попробую посмотреть на параметры функции, запускающей процессы (CreateProcess): может, там есть что-то типа проверки - запущен ли уже процесс с указанным именем.
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
c0ff
Продвинутый форумчанин
Предупреждений : 2
СообщениеДобавлено: Чт 3-04-08 : 20-30    Заголовок сообщения: Ответить с цитатой

в таком случае можно сделать простую оболочку - запускальщик - которая будет устанавливать данный мутекс:

Код:

int main(int ac, char *arg[])
{

HANDLE h = CreateMutex(NULL, FALSE, arg[0]);
   if(GetLastError() == ERROR_ALREADY_EXISTS)
   {
      // Приложение уже запущено
      return 0;
   }
   // Приложение запущено в первый раз
   // ...

   CloseHandle(h);

   
   
   
   h=CreateProcess("RenamedApp.exe",....
   .....
   WaitForSingleObject(h,...

   CloseHandle(h);



а приложение, запускаемое - переименовать.
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
Vicor
Начинающий
СообщениеДобавлено: Пт 4-04-08 : 00-45    Заголовок сообщения: Ответить с цитатой

Цитата:
Я только не пойму, почему компилятор не даёт мне осуществить эту идею (см. пост с обибками раньше)?

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

Можно попробовать еще один вариант: использовать функцию FindWindow для поиска окна с заданным именем. Если окно найдено, то приложение уже выполняется.

Код:

HWND h = FindWindow(NULL, "Калькулятор");
if(h == NULL)
{
   // Приложение не запущено
   CreateProcess(...);
}
else
{
   // Приложение запущено, делаем его активным   
   SetForegroundWindow(h);
}
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
AlexRock
Гуру
СообщениеДобавлено: Пт 4-04-08 : 19-40    Заголовок сообщения: Ответить с цитатой

Vicor писал(а):
Можно попробовать еще один вариант: использовать функцию FindWindow для поиска окна с заданным именем. Если окно найдено, то приложение уже выполняется.




Код:

HWND h = FindWindow(NULL, "Калькулятор");

if(h == NULL)

{

   // Приложение не запущено

   CreateProcess(...);

}

else

{

   // Приложение запущено, делаем его активным   

   SetForegroundWindow(h);

}


О, майн Год (я стал верующим на эти несколько секунд, когда у меня ПОЛУЧИЛОСЬ ЭТО!). Всё пашет!
Vicor
Вы потакаете моей лени - теперь я забью на Mutex, пока жареный петух опять не клюнет. ))) Большое вам спасибо! И всем, кто мне помогал здесь.
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
dlnsk
Гуру
СообщениеДобавлено: Пт 4-04-08 : 23-44    Заголовок сообщения: Ответить с цитатой

AlexRock
Мьютекс тебе и не помог бы, поскольку нет исходников запускаемых прог, а применять его нужно именно там...
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение Посетить сайт автора  
Показать сообщения:   
Ответить на тему    Форум АДСЛ КлубаЦИФРОВОЙ ФЛЕЙМ :)ПРОГРАММИРОВАНИЕ Часовой пояс: GMT + 7
На страницу 1 2
Страница 1 из 2

 

 
Аватары: Вкл|Выкл   ЮзерИнфо: Вкл|Выкл   Подписи: Вкл|Выкл
Перейти:  
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете вкладывать файлы
Вы можете скачивать файлы