Форум — Ответы     (  К темам )
 ?  Akela: Проблема с ShowWindow (05-02-2003 16:35:45)
при запуске программы проверяю ее наличие в системе (повторный запуск)
Если есть — пытаюсь отобразить уже запущенный экземпляр через ShowWindow
и закрываю новый.
Форма отображается, но если она была свернута(minimized) то после такой "экзекуции" намертво отказывается сворачиться ??????
 Andrew (05-02-2003 17:39:18)
A с каким параметром nCmdShow ты вызываешь ShowWindow?
 Akela (05-02-2003 19:19:41)
Собственно перебрал почти все — SW_SHOW, SW_RESTORE, SW_SHOWNORMAL, SW_SHOWDEFAULT, SW_SHOWNA
 Павел (05-02-2003 23:40:20)
Возьмите да проверьте, свернута она или нет
if(Form1->WindowState == wsMinimized) Form1->WindowState == wsNormal;
 Павел (05-02-2003 23:41:40)
Извините, вот так:

if(Form1->WindowState == wsMinimized) Form1->WindowState = wsNormal;
 Akela (06-02-2003 02:17:56)
И каким чудом мне добраться до свойств формы, если я ее, при наличии, только по HANDLE и отлавливаю?
 Petro (06-02-2003 13:13:24)
Попробуй так: ShowWindow(handle, SW_SHOWNORMAL). В обработчике событий смотришь:
если SW_SHOWNORMAL, делаешь Form1->WindowState = wsNormal.

2 ALL:
BringWindowToTop(h);
SetForegroundWindow(h);
ShowWindow(h, SW_SHOWNORMAL);
В VC++ такое работает без проблем.
 Akela (08-02-2003 04:11:16)
проблема все та же: все это конечно работает, но....
каого ..... эта ........ форма отказывается в последствии сворачиваться!!??
 Petro (08-02-2003 10:48:15)
Отказывется потому, что она свернута, несмотря на то, что ее видно.
 Akela (09-02-2003 07:51:18)
и как с этим бороться?
в крайнем случае, может кто подскажет другой путь упреждения повторного запуска?
 Petro (10-02-2003 10:44:36)
Есть такой путь — создать мутекс.
 Akela (10-02-2003 11:58:00)
ачто это за зверь такой, и с чем его едят?
 Dr.Phoenix (17-02-2003 14:42:11)
Вот, это кусок из методы 2-го курса
-------------------------------------------------

Мьютексы и критические секции

Предположим, что необходимо разработать пакет программ, которые одновременно работают с общим файлом данных — вносят в него какие-либо изменения. Программы данного пакета могут работать одновременно — например, одна из них записывает в файл данные, приходящие от каких-либо датчиков, подключенных к компьютеру, а другая позволяет пользователю редактировать данные в файле. Что произойдет, если одна из программ откроет файл для записи, начнет запись данных, а затем ее выполнение будет прервано операционной системой, и управление будет передано другой программе, которая попытается открыть тот же файл? Если файл был открыт для эксклюзивного доступа, то вторая программа не сможет его открыть — возникнет ошибка. Если файл был открыт для общего доступа, то данные, записываемые обеими программами, перемешаются — нарушится структура файла данных. Для того, чтобы избежать подобной ситуации, необходимо вводить какой-либо флаг, который должен сигнализировать занятость ресурса. Программа, желающая получить доступ к данному ресурсу, должна считать состояние флага, проверить, не установлен ли флаг (свободен ли ресурс), и если он еще не установлен, то установить флаг и занять ресурс. В качестве флага может использоваться какой-либо признак, разделяемый между различными процессами, например, наличие или отсутствие определенного файла и т.д. Данный алгоритм, хотя и применяется в некоторых системах, имеет большой недостаток. Предположим, что программа считала состояние флага и была прервана ОС, управление было передано другой программе, которая установила флаг и получила доступ к ресурсу, затем управление было передано вновь первой программе. Она приступает к следующей стадии — анализу состояния флага, но его состояние было считано до того, как его изменила вторая программа, и возникает ошибка. Таким образом, необходимо обеспечить блокирование доступа к флагу других процессов, пока какой-либо процесс считывает и анализирует его состояние. Для этого в Win32 API введен объект под названием мьютекс (сокращение от «mutual exception» — «взаимное исключение»). Поток может попытаться завладеть мьютексом. Если им не владеет никакой другой поток, то данный поток станет владельцем мьютекса. После этого никакие другие потоки не смогут завладеть данным мьютексом до тех пор, пока первый поток не освободит его. Таким образом, мьютекс, как и разделяемый ресурс, может одновременно принадлежать только одному потоку, что исключает конфликты между потоками. В то же время, поток — владелец мьютекса может стать владельцем мьютекса повторно. Если поток присваивал себе мьютекс несколько раз, то он должен освободить его такое же количество раз.
Сигнальным состоянием мьютекса является его свободное состояние, то есть при проверке состояния свободного мьютекса функция WaitForSingleObject вернет значение WAIT_OBJECT_0. Если мьютекс был занят и не освободился до окончания периода ожидания, то будет возвращено значение WAIT_TIMEOUT, а если процесс, владеющий мьютексом, завершился, не освободив его, то система освобождает мьютекс и функция WaitForSingleObject возвращает значение WAIT_ABANDONED. Набор функций Win32 API для работы с мьютексами:

CreateMutex-Создает новый мьютекс или открывает уже существующий
OpenMutex-Открывает существующий мьютекс
ReleaseMutex-Освобождает мьютекс и делает его доступным для других потоков

Необходимо помнить, что мьютекс сам по себе не обеспечивает управления ресурсом. Он только указывает программисту (при правильном использовании), что ресурс был занят, а управление ресурсом необходимо реализовывать самостоятельно.
Ниже приведен пример консольного Win32 приложения на языке С++, реализующего синхронизацию процессов с помощью мьютексов. В качестве синхронизируемых процессов выступают запущенные пользователем экземпляры данного приложения. При запуске нескольких экземпляров данного приложения, первый запущенный процесс выведет на экран окно с сообщением о захвате мьютекса, и до тех пор, пока данное окно не будет закрыто, другие приложения не смогут вывести свои окна. После закрытия окна мьютекс освобождается и захватывается другим процессом.


#include <windows.h>
#include <iostream.h>
void main()
{
HANDLE mtx=CreateMutex (NULL, FALSE, "MyMutexName");
cout <<"Проверяем мьютекс\n";
cout.flush();
WaitForSingleObject(mtx, INFINITE);
cout <<"Мьютекс получен! \n";
cout.flush();
MessageBox (NULL, "Программа обладает мьютексом", "MUTEX", MB_OK);
ReleaseMutex(mtx);
CloseHandle(mtx);
}

Механизм мьютексов, хоть мьютекс и захватывается конкретным потоком, предназначен, в основном, для синхронизации процессов. Конечно, мьютексы можно использовать и для синхронизации потоков внутри одного процесса, но для этого есть более подходящее решение — механизм критических секций. Критическая секция — это участок кода, одновременное выполнение которого несколькими потоками недопустимо.
Чтобы защитить участок кода от совместного использования несколькими потоками, определите переменную типа CRITICAL_SECTION и передайте ее адрес функции InitializeCriticalSection. К этой функции следует обращаться из главного потока вашей программы (обычно из потока main). В начале критической секции кода следует расположить обращение к функции EnterCriticalSection. Если в этот момент критическая секция исполняется каким-либо другим потоком, исполнение потока, обратившегося к EnterCriticalSection, будет блокировано до тех пор, пока критический участок не освободится. Если вы не хотите блокировать работу потока и желаете, чтобы во время ожидания освобождения критической секции поток выполнял какую-либо другую полезную работу, вы можете использовать вызов TryEnterCriticalSection. Этот вызов возвращает значение TRUE в случае, если критический участок кода никем не занят. Если вызов вернул значение FALSE, поток может выполнить какую-либо другую работу, а затем вновь обратиться к TryEnterCritlcalSection.
Вызов TryEnterCriticalSecflon будет продолжать возвращать FALSE, а вызов EnterCriticalSection будет продолжать блокировать выполнение потоков до тех пор, пока поток, выполняющий критическую секцию, не обратится к LeaveCriticalSection. Таким образом, чаще всего функция, содержащая критический участок кода, выглядит следующим образом:

void one_at_a_time_please()
{
EnterCriticalSection(&section): // инициализация выполняется
// в другом месте
// здесь расположен критический участок кода
LeaveCriticalSection(&section);
}

Другой вариант аналогичной функции:

BOOL only_one_at_a_time()
{
if (!TryEnterCriticalSection (&section)) // инициализация выполняется
// в другом месте
return FALSE; // функция занята другим потоком
// здесь расположен критический участок кода LeaveCriticalSection(Ssection); return TRUE; // мы сделали это!
}

Если вы больше не нуждаетесь в критической секции, вы обратитесь к DeleteCriticalSection, чтобы уничтожить ее. При этом система освободит ресурсы, связанные с критической секцией.
 Георгий (19-02-2003 17:22:03)
Спасибо Dr.Phoenix. Очень познавательно — я это пытался понять через MS SDK, что в комплекте с BCB, но до конци не понял и использовал Билдеровские классы (TMultiReadWriteExclusiveSynhronizer). Скажи, где это на втором курсе такие методички раздают — у меня такого не было...