• 15 апреля стартует «Курс «SQL-injection Master» ©» от команды The Codeby

    За 3 месяца вы пройдете путь от начальных навыков работы с SQL-запросами к базам данных до продвинутых техник. Научитесь находить уязвимости связанные с базами данных, и внедрять произвольный SQL-код в уязвимые приложения.

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

    Запись на курс до 25 апреля. Получить промодоступ ...

Mfc(ехе)

  • Автор темы solova
  • Дата начала
Статус
Закрыто для дальнейших ответов.
S

solova

Есть MFC програмка (exe)
запускаю этот ехе - открывается моё окно
запускаю ещё раз ехе - открывается ещё одно окно
...
...
Как сделать чтоб программа не запускалась второй раз?
Какие есть варианты?
вычитал такое, но как реализовать?<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Вариант</div></div><div class="sp-body"><div class="sp-content">Ваша функция WinMain может также ограничить вашу прикладную программу единственным экземпляром. Создайте именованный mutex-объект (объект-статист), используя функцию CreateMutex. Если функция GetLastError возвращает ERROR_ALREADY_EXISTS, другой образец вашей прикладной программы существует (он создан mutex-объектом), и Вы должны выйти из вашей WinMain. Это то что надо, или не то?
 
L

lazybiz

Это выглядит как-то вот так:
C++:
// activate an application with a window with a specific class name
BOOL CMyApp::FirstInstance()
{
CWnd *pWndPrev, *pWndChild;

// Determine if a window with the class name exists...
pWndPrev = CWnd::FindWindow(_T("MyNewClass"), NULL);
if (NULL != pWndPrev)
{
// If so, does it have any popups?
pWndChild = pWndPrev->GetLastActivePopup();

// If iconic, restore the main window
if (pWndPrev->IsIconic())
pWndPrev->ShowWindow(SW_RESTORE);

// Bring the main window or its popup to the foreground
pWndChild->SetForegroundWindow();

// and you are done activating the other application
return FALSE;
}

return TRUE;
}
Суть в том, чтобы найти окно с таким же именем класса. Если такое есть, значит передать ему фокус и не продолжать выполнение нового приложения.
На сколько мне известно, то же самое можно сделать через атомы, но, честно говоря, мне просто лень искать...
 
S

solova

Суть уловил. но что будет если моё окно не особо активно,например в трее воляется, что вернёт GetLastActivePopup()? Ведь оно вроде возвращает хвнд "самого последнего".
 
A

a0z

Делай через мутекс, не ошибёшся.

Как-то так:
m_hMutex - член класса CApp (или как оно там называется. не окна а именно приложения)
Во время инициализации приложения:

bool isFirstInstance = false;

m_hMutex = ::CreateMutex(NULL, FALSE, L"My Super program");
if (m_hMutex != NULL)
{
if :):GetLastError() == ERROR_ALREADY_EXISTS)
{
::CloseHandle(m_hMutex);
m_hMutex = NULL;
}
else
{
isFirstInstance = true;
}
}

if(!firstInstance)
выходим

Вариант с оконным класом в серьёзных приложениях не канает, но для лабы сгодится.

Во-первых если понадобится написать что-то ДО инициализации окна, то мы не сможем сказать, первый ли это инстанс.
А во вторых, этот способ не всегда будет правильно работать. Допстим есть 2 конкурирующих инстанса.
1: Вызвал CWnd::FindWindow, получил NULL и тут его шедулер прерывает.
2: Вызывает CWnd::FindWindow, получает NULL, создаёт окно. Шедулер переключает обратно на 1.
1: Создаёт окно

итого - два приложения.
 
L

lazybiz

Суть не в функции GetLastActivePopup, суть в результате FindWindow. Если окно найдено, значит другой экземпляр запущен.
 
L

lazybiz

А еще лучше создать глобальный атом (GlobalAddAtom) в сомом начале программы с уникальный именем, а перед этим поставить проверку (GlobalFindAtom) существует уже такой или нет.
 
A

a0z

Суть не в функции GetLastActivePopup, суть в результате FindWindow. Если окно найдено, значит другой экземпляр запущен.

А еще лучше создать глобальный атом (GlobalAddAtom) в сомом начале программы с уникальный именем, а перед этим поставить проверку (GlobalFindAtom) существует уже такой или нет.

Суть в том, что оба варианта не атомарны, поскольку предполагают создание и проверку различными функциями.

Это может привести к ошибке.
 
L

lazybiz

Суть в том, что оба варианта не атомарны, поскольку предполагают создание и проверку различными функциями.

Это может привести к ошибке.
Чиво чиво!??) "атомарны" !??))) Не знаю что ты под этим подразумеваешь...)) Но очень хотелось бы узнать.
Да, и к какой же ошибке это может привести?

Добавлено: Пусть они "не атомарны", зато они логичны.
 
A

a0z

Использование этих функций может привести к ошибке.

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

Моя логика подсказывает, что лучше верный вариант, чем не верный. Тем более, что по сложности они примерно равны.
 
L

lazybiz

Хорошо, не спорю. Вариант с Mutex самый лучший.
 
S

solova

На счёт трея: у меня было такое соображение ,что GetLastActivePopup() возвращает хэндл последнего окна которое было в "фокусе" а если прога создаёт при включении иконку в трее то оно точно не в фокусе.
но почитав про функцию всё понял.
 
S

solova

ну во рабочий примерчик<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">код</div></div><div class="sp-body"><div class="sp-content">
C++:
HANDLE hMutex = ::CreateMutex( NULL, FALSE, L"MyMUTEX-123456789");
if (GetLastError()==ERROR_ALREADY_EXISTS ||GetLastError()==ERROR_ACCESS_DENIED)
{
MessageBox(L"Ещё тыркнешь, format сделаю.",L"Слыш ТЫ",NULL);
PostQuitMessage(0);
}
вставляю в самое начало CMyDlg::OnInitDialog() и всё работает.
но есть два вопросика
1) туда ли я вставляю(какая самая первая функция выполняется в MFC)
2) нужно ли мне проверять на "ERROR_ACCESS_DENIED"? ведь она вроде только когда мьютекс чем то занят, а у меня он просто создан и висит неиспользуемый
 
S

solova

мне нравится ваше "можно попробовать"
я почитал про PostQuitMessage и ExitProcess
дело в том что у меня мьютекс и ещё ДЛЛ(с хуком) к проекту прилагается
оказалось что ExitProcess c ними может не подружится<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">цицюля</div></div><div class="sp-body"><div class="sp-content">"При этом теряются все данные, которые процесс не успел переписать из памяти на диск." в принципе у меня ничего не записывается/читается(через мутех и длл), но мало ли что ещё придумаю
а PostQuitMessage ставит WM_QUIT в очередь, и всё успевает выполнится без потерь
 
L

lazybiz

Просто ты писал:
... у меня он просто создан и висит неиспользуемый
поскольку код ты не показываешь, я решил что у тебя PostQuitMessage(0) не срабатывает (если я вообще правильно тебя понял). Трудновато искать иголку в стоге сена с завязанными глазами.
 
A

a0z

Насколько я помню, надо найти функцию InitInstance у наследника CWinApp (не у диалога).

И вернуть FALSE, если инстанс уже существует.
А в ExitInstance закрыть мутекс.

 
S

solova

ExitInstance я не нашёл, надо самому создавать? но я сделал по другому<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">код</div></div><div class="sp-body"><div class="sp-content">
C++:
BOOL CMyApp::InitInstance()
{
HANDLE hMutex = ::CreateMutex( NULL, FALSE, L"MyMUTEX-123456789");
if (GetLastError()==ERROR_ALREADY_EXISTS)
{
MessageBox(NULL,L"Ещё тыркнешь, format сделаю.",L"Слыш ТЫ",NULL);
ReleaseMutex(hMutex);
CloseHandle(hMutex);
return FALSE;
}
.......
.......
return FALSE;
}
кстати на окне по дэфу создаются кнопки OK и Cancel обработчика на них нету но они совершают закрытие
так вот как от этих кнопок избавится (достаточно ли просто удалить с диалога? и строчки из выше стоящего кода)
 
A

a0z

Да, можно просто удалить кнопки. И проверку возврата.
 
Статус
Закрыто для дальнейших ответов.
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!