Mfc(ехе)

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

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

    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. Это то что надо, или не то?
     
  2. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    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 Гость

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

    a0z Well-Known Member

    Регистрация:
    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

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

    lazybiz Well-Known Member
    C\C++ Team

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

    a0z Well-Known Member

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

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

    lazybiz Well-Known Member
    C\C++ Team

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

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

    a0z Well-Known Member

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

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

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

    lazybiz Well-Known Member
    C\C++ Team

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

    lazybiz Well-Known Member
    C\C++ Team

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

    lazybiz Well-Known Member
    C\C++ Team

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

    solova Гость

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

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

    lazybiz Well-Known Member
    C\C++ Team

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

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

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

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

    lazybiz Well-Known Member
    C\C++ Team

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

    a0z Well-Known Member

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

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

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

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

    a0z Well-Known Member

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

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