Mfc(ехе)

Тема в разделе "MS Visual C++", создана пользователем solova, 27 мар 2011.

Статус темы:
Закрыта.
  1. solova

    solova Гость

    Репутация:
    0
    Есть 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. Это то что надо, или не то?
     
  2. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Репутация:
    0
    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    Это выглядит как-то вот так:
    Код (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;
    }
    Суть в том, чтобы найти окно с таким же именем класса. Если такое есть, значит передать ему фокус и не продолжать выполнение нового приложения.
    На сколько мне известно, то же самое можно сделать через атомы, но, честно говоря, мне просто лень искать...
     
  3. solova

    solova Гость

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

    a0z Well-Known Member

    Репутация:
    0
    Регистрация:
    15 мар 2011
    Сообщения:
    109
    Симпатии:
    0
    Делай через мутекс, не ошибёшся.

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

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

    lazybiz Well-Known Member
    C\C++ Team

    Репутация:
    0
    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    Суть не в функции GetLastActivePopup, суть в результате FindWindow. Если окно найдено, значит другой экземпляр запущен.
     
  6. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Репутация:
    0
    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    А еще лучше создать глобальный атом (GlobalAddAtom) в сомом начале программы с уникальный именем, а перед этим поставить проверку (GlobalFindAtom) существует уже такой или нет.
     
  7. a0z

    a0z Well-Known Member

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

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

    lazybiz Well-Known Member
    C\C++ Team

    Репутация:
    0
    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    Чиво чиво!??) "атомарны" !??))) Не знаю что ты под этим подразумеваешь...)) Но очень хотелось бы узнать.
    Да, и к какой же ошибке это может привести?

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

    a0z Well-Known Member

    Репутация:
    0
    Регистрация:
    15 мар 2011
    Сообщения:
    109
    Симпатии:
    0
    Использование этих функций может привести к ошибке.

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

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

    lazybiz Well-Known Member
    C\C++ Team

    Репутация:
    0
    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    Хорошо, не спорю. Вариант с Mutex самый лучший.
     
  11. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Репутация:
    0
    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    Может я где-то что-то недочитал... какое окно в каком трее?
     
  12. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Репутация:
    0
    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    А. Это уже не актуально.
     
  13. solova

    solova Гость

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

    solova Гость

    Репутация:
    0
    ну во рабочий примерчик<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"? ведь она вроде только когда мьютекс чем то занят, а у меня он просто создан и висит неиспользуемый
     
  15. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Репутация:
    0
    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    нет. ERROR_ALREADY_EXISTS достаточно.

    По поводу MFC ничего сказать не могу.

    Добавлено: PostQuitMessage(0); можно попробовать заменить на ExitProcess( 0 );
     
  16. solova

    solova Гость

    Репутация:
    0
    мне нравится ваше "можно попробовать"
    я почитал про 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 в очередь, и всё успевает выполнится без потерь
     
  17. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Репутация:
    0
    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    Просто ты писал:
    поскольку код ты не показываешь, я решил что у тебя PostQuitMessage(0) не срабатывает (если я вообще правильно тебя понял). Трудновато искать иголку в стоге сена с завязанными глазами.
     
  18. a0z

    a0z Well-Known Member

    Репутация:
    0
    Регистрация:
    15 мар 2011
    Сообщения:
    109
    Симпатии:
    0
    Насколько я помню, надо найти функцию InitInstance у наследника CWinApp (не у диалога).

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

    http://msdn.microsoft.com/en-us/library/ae...v=vs.80%29.aspx
     
  19. solova

    solova Гость

    Репутация:
    0
    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 обработчика на них нету но они совершают закрытие
    так вот как от этих кнопок избавится (достаточно ли просто удалить с диалога? и строчки из выше стоящего кода)
     
  20. a0z

    a0z Well-Known Member

    Репутация:
    0
    Регистрация:
    15 мар 2011
    Сообщения:
    109
    Симпатии:
    0
    Да, можно просто удалить кнопки. И проверку возврата.
     
Статус темы:
Закрыта.

Поделиться этой страницей