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. Это то что надо, или не то?
 
Это выглядит как-то вот так:
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;
}
Суть в том, чтобы найти окно с таким же именем класса. Если такое есть, значит передать ему фокус и не продолжать выполнение нового приложения.
На сколько мне известно, то же самое можно сделать через атомы, но, честно говоря, мне просто лень искать...
 
Суть уловил. но что будет если моё окно не особо активно,например в трее воляется, что вернёт GetLastActivePopup()? Ведь оно вроде возвращает хвнд "самого последнего".
 
Делай через мутекс, не ошибёшся.

Как-то так:
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: Создаёт окно

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

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

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

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

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

Добавлено: Пусть они "не атомарны", зато они логичны.
 
Использование этих функций может привести к ошибке.

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

Моя логика подсказывает, что лучше верный вариант, чем не верный. Тем более, что по сложности они примерно равны.
 
Хорошо, не спорю. Вариант с Mutex самый лучший.
 
На счёт трея: у меня было такое соображение ,что GetLastActivePopup() возвращает хэндл последнего окна которое было в "фокусе" а если прога создаёт при включении иконку в трее то оно точно не в фокусе.
но почитав про функцию всё понял.
 
ну во рабочий примерчик<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"? ведь она вроде только когда мьютекс чем то занят, а у меня он просто создан и висит неиспользуемый
 
мне нравится ваше "можно попробовать"
я почитал про 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 в очередь, и всё успевает выполнится без потерь
 
Просто ты писал:
... у меня он просто создан и висит неиспользуемый
поскольку код ты не показываешь, я решил что у тебя PostQuitMessage(0) не срабатывает (если я вообще правильно тебя понял). Трудновато искать иголку в стоге сена с завязанными глазами.
 
Насколько я помню, надо найти функцию InitInstance у наследника CWinApp (не у диалога).

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

 
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 обработчика на них нету но они совершают закрытие
так вот как от этих кнопок избавится (достаточно ли просто удалить с диалога? и строчки из выше стоящего кода)
 
Да, можно просто удалить кнопки. И проверку возврата.
 
Статус
Закрыто для дальнейших ответов.
Мы в соцсетях:

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