Теперь посмотрим, как можно будет
Теперь посмотрим, как можно будет показать найденную первую копию. Вариантов 'поискать и показать форму', в интернете, огромная масса. Тестовая процедура и сама функция выглядят так:
Unit testAppl; ... procedure TTestUnitAppl.TestShowPrevInstance; begin Check(ShowPrevInstance('DUnit'), strFailedTest); end; unit Appl; ... function ShowPrevInstance(Name: string): boolean; var PrevInstance: HWND; begin Result := False; PrevInstance := FindWindow('TApplication', PChar(Name)); if PrevInstance <> 0 then begin if IsIconic(PrevInstance) then ShowWindow(PrevInstance, SW_RESTORE); SetForegroundWindow(PrevInstance); Result := True; end; end; |
Компилируем, запускаем, проверяем - все работает, как требуется. Следует отметить, что в данном случае, тестировалось только возвращаемое
ShowPrevInstance значение, сам эффект 'показа' незаметен. По этому, что бы ни уподобляться тому сапожнику, который без сапог, внесем в
testMiniProg.dpr изменения, добавим в секцию
uses модуль
Appl и следующий код:
program testMiniProg; uses Appl in '..\SOURCE\Appl.pas', Forms, TestFrameWork, GUITestRunner, testAppl in 'testAppl.pas', testUnit in 'testUnit.pas' {testForm}; {$R *.res} begin if FindAndShowPrevInstance('DUnit') then Halt else try Application.Initialize; Application.Title := 'DUnit'; GUITestRunner.RunRegisteredTests; finally StopPrevInstance; end; end. |
В модуль
Appl.pas, поместим функцию
FindAndShowPrevInstance, которая будет искать и активизировать предыдущую копию программы. Её тестирование проведем на функциональном уровне, так как технологическое тестирование, хоть и возможно, но реализовывать его будет обременительно. Впрочем, желающие могут попробовать, не забудьте только мне показать, очень интересно.
function FindAndShowPrevInstance(Name: string): boolean; begin Result := FindPrevInstance(Name); if Result then ShowPrevInstance(Name); end; |
Компилируем, запускаем, пробуем запустить вторую копию - у меня всё, как и предполагалось. Ну что же, можем считать, что функциональные тесты данная функция прошла. Есть один момент, который нужно учитывать. Не очень удобно то, что '
DUnit', или какое-то другое, милое вашему сердцу заветное слово, приходится писать два раза. Мне, к сожалению, так и не удалось приравнять
Application.Title ни константе, ни переменной. Все время возникала ошибка
dcc32.exe, по-видимому, из-за того, что данное значение используется самим
Delphi. Возможно изменение, в виде переноса проверки
FindAndShowPrevInstance в секцию
initialization модуля
Appl.pas,
StopPrevInstance в секцию
finalization, а сам
unit прописать в
uses dpr вашей программы самым
ПЕРВЫМ. В принципе, я обычно так и делаю, в данном же случае пример просто показательный, потому и несколько упрощенный. Не сомневаюсь, даже данный подход можно улучшить. Особенность передаваемого
FindAndShowPrevInstance значения в том, что оно должно быть такое же, как и имя главной формы программы, в противном случае невозможно будет правильное выполнение
StopPrevInstance. Конечно, проверка мьютекса будет выполнена, и 'лишнее' приложение буде закрыто, но активизации первой копии не произойдет. Если кого-то не устраивает такое положение дел, например, этот кто-то, всегда дает одно и тоже имя главному модулю своих программ, то всё можно поправить. Просто расширьте число предаваемых функции параметров - отдельно имя мьютекса, отдельно имя главного окна.
Содержание Назад Вперед