![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как правильно активизировать окно
DelphiLexx © (2006-10-16 11:41:00)Мое приложение должно работать в одном экземпляре для этого я используя:
function
CheckAppRun:
integer;
var
Map: THandle;
begin
Map := CreateFileMapping($FFFFFFFF, nil, PAGE_READONLY, 0, 32,
'%af_src_comm_0');
if Map = 0 then
Result := -1
else if GetLastError = ERROR_ALREADY_EXISTS then
Result := 1
else
Result := 0
end;
function
ActivatePreviousInstance(WndClass: PChar): boolean;
var
Wnd: HWND;
begin
Result := false;
if (CheckAppRun = 1) then
begin
if (WndClass <> nil) then
begin
{если окно программы указано сделать его активным в системе}
Wnd := FindWindow(WndClass, nil);
if (Wnd <> 0) then
begin
{Хочу отобразить мое приложение, но оно не отображается}
SwitchToThisWindow(Wnd, True);
end;
end
else
MessageBox(0, 'Приложение уже запущено!', 'Сообщение',
MB_ICONINFORMATION or MB_OK);
Result := true;
end;
end;
if ActivatePreviousInstance('TMainForm') then Halt(1);
Для отображения своего приложения я использовал SwitchToThisWindow(Wnd, True), но оно не отображается. Я использовал ShowWindow(Wnd, SW_SHOWMAXIMIZED) окно отображается, но после такой операции его нельзя свернуть.
Так как же правильно отобразить свое приложение не зависимо от того минимизировано оно или нет?
Leonid Troyanovsky (2006-10-17 20:20:00) [1]
> Leonid Troyanovsky © (17.10.06 20:07) [15]
> Т.е., если SendMessageTO успешно - активируем предыдущую
> копию,
активируем предыдущую копию и Halt(..),
иначе - вызываем inherited
--
Regards, LVT.
Leonid Troyanovsky (2006-10-17 20:07:00) [2]
> gdaujk © (16.10.06 23:06) [14]
>> Ну, и для приложений с формами можно предложить
> Так предложите. Или хотя бы намекните :-)
Например:
В CreateWnd (override) главной формы делаем (до inherited)
EnumWindows для поиска окон формы по ее классу, и,
в случае обнаружения такого окна, посылаем ему через
SendMessageTimeOut(wnd, WM_COPYDATA,
параметры комстроки, а также, в cds.dwData - искомый uid.
А в обработчике WM_COPYDATA главной формы полученный uid
сравнивается с собственным, и, в случае равенства,
возвращается (после приема комстроки) Result <> 0.
Т.е., если SendMessageTO успешно - активируем предыдущую копию,
иначе - вызываем inherited для создания окна формы.
Вот, собс-но, вся схема.
--
Regards, LVT.
gdaujk (2006-10-16 23:06:00) [3]
> Leonid Troyanovsky © (16.10.06 22:15) [13]
> Ну, и для приложений с формами можно предложитьвполне сравнимый
> способ
>
Так предложите. Или хотя бы намекните :-)
Leonid Troyanovsky (2006-10-16 22:15:00) [4]
> gdaujk © (16.10.06 21:09) [12]
> UNIQUE_APP_STR = '{FC9D27F6-D173-4CF6-8A9A-3A2197C72390}';
> //желательно изменить
Не желательно, а : Обязательно изменить!
Вообще-то, подобные вещи должны браться из реестра.
Т.е., сделать в HKCU раздел формата
\Software\CompanyName\ProductName\..
где второе, третье и др. брать из Version Info,
ключ ActivatePrevInstance (REG_DWORD) 0x1.
Т.е., имя проекции файла формировать из уникальной цепочки.
Кроме того, для активации предыдущей копии полезно
передавать дополнительно параметры комстроки.
Этого можно добиться, например, перечитыванием mmf
при Application.OnActivate. Хотя, это потребует некоторых
усилий по синхронизации. Например, четыре байта файла
использовать для переменной, которая будет
InterLockedCompareExchange.
Ну, и для приложений с формами можно предложить
вполне сравнимый способ без использования
объектов ядра.
--
Regards, LVT.
gdaujk (2006-10-16 21:09:00) [5]...а сколько копий было сломано...
unit gdaOneAppByFileMapping;
interface
var
MIError: Integer;
const
MI_ERROR_NONE = 0;
MI_ERROR_CREATINGMAP = 1;
MI_ERROR_MAPPINGFILE = 2;
function GetMEError(): Integer;
implementation
uses Windows, Forms;
var
hMap: THandle;
UniqueMes: Integer;
const
UNIQUE_APP_STR = '{FC9D27F6-D173-4CF6-8A9A-3A2197C72390}'; //желательно изменить
function GetMEError(): Integer;
begin
Result := MIError;
end;
procedure InitInstance;
var
pFile: Pointer;
hApp: HWND;
const
pFileSize = SizeOf(HWND);
begin
hMap := CreateFileMapping(INVALID_HANDLE_VALUE,
nil,
PAGE_READWRITE,
0,
pFileSize,
UNIQUE_APP_STR);
if GetLastError = ERROR_ALREADY_EXISTS
then
begin
Application.ShowMainForm := False;
pFile := MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
if pFile <> nil
then
begin
hApp := HWND(pFile^);
ShowWindow(hApp, SW_SHOWNORMAL);
SetForegroundWindow(hApp);
UnmapViewOfFile(pFile);
end
else MIError := MIError or MI_ERROR_MAPPINGFILE;
Application.Terminate;
end
else
if hMap = 0
then MIError := MIError or MI_ERROR_CREATINGMAP
else
begin
pFile := MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
if pFile <> nil
then
begin
CopyMemory(pFile, @Application.Handle, pFileSize);
UnmapViewOfFile(pFile);
end
else MIError := MIError or MI_ERROR_MAPPINGFILE;
end;
end;
initialization
UniqueMes := RegisterWindowMessage(UNIQUE_APP_STR);
InitInstance;
finalization
if hMap <> 0
then CloseHandle(hMap);
end.
Leonid Troyanovsky (2006-10-16 18:35:00) [6]
> RWolf © (16.10.06 18:01) [10]
> Или мы говорим о разных вещах?
Мои утверждения вполне, IMHO, применимы
к любым не-foreground windows приложениям.
--
Regards, LVT.
RWolf (2006-10-16 18:01:00) [7]
> Оное и обсуждалось.При получении сообщения не-foreground
> приложение пытается сделать себя (другого) foreground, что
> запрещено политикой MS(и правильно запрещено, IMHO).
Просто я как раз такой механизм использую для восстановления программы из трея при запуске 2 экземпляра.
Или мы говорим о разных вещах?
Leonid Troyanovsky (2006-10-16 17:50:00) [8]
> RWolf © (16.10.06 17:39) [8]
> мое предложение заключалось в том, что делать foreground-
> ом приложение будет именно себя, свой экземпляр; см. [1]
Оное и обсуждалось.
При получении сообщения не-foreground приложение пытается
сделать себя (другого) foreground, что запрещено политикой MS
(и правильно запрещено, IMHO).
--
Regards, LVT.
RWolf (2006-10-16 17:39:00) [9]мое предложение заключалось в том, что делать foreground-ом приложение будет именно себя, свой экземпляр; см. [1]
Leonid Troyanovsky (2006-10-16 17:26:00) [10]
> RWolf (16.10.06 17:17) [5]
> Как-то так:
Не так.
Не foreground приложение не может сделать себя
(другого) foreground.
Т.е., посылка подобных сообщений бесполезна.
--
Regards, LVT.
Leonid Troyanovsky (2006-10-16 17:22:00) [11]
> DelphiLexx © (16.10.06 17:09) [4]
> Если окно приложения свернуто, то твой код не отображает
Вполне отображает.
Только, окно приложения - это окно класса (windows) TApplication.
Если есть хендл любого другого окна приложения (дельфи, билдер),
то окно приложения можно найти как
happ := GetWindowLong(wnd, GWL_HWNDPARENT)
--
Regards, LVT.
RWolf (2006-10-16 17:17:00) [12]> Каким образом?
Как-то так:
Application.Restore;
if Application.MainForm.WindowState = wsMinimized then
Application.MainForm.WindowState := wsNormal;
Application.MainForm.Visible := True;
SetForegroundWindow(Application.Handle);
DelphiLexx (2006-10-16 17:09:00) [13]
> if IsIconic(hWnd) then
> ShowWindow(hWnd, SW_RESTORE);
> SetForegroundWindow(hWnd);
Если окно приложения свернуто, то твой код не отображает его.
clickmaker (2006-10-16 17:03:00) [14]if IsIconic(hWnd) then
ShowWindow(hWnd, SW_RESTORE);
SetForegroundWindow(hWnd);
DelphiLexx (2006-10-16 16:36:00) [15]
> посылать найденному окну пользовательское сообщение, пусть
> само разворачивается.
Каким образом?
RWolf (2006-10-16 16:34:00) [16]посылать найденному окну пользовательское сообщение, пусть само разворачивается.