Текущий архив: 2006.02.26;
Скачать: CL | DM;
Вниз
Вторая копия программы ! Найти похожие ветки
← →
Конопелька (2005-12-07 00:12) [0]Здравтвуйте !
Подскажите пожалуйста исключение варианта запуска второй копии программы !! и что б при повторном запуске программы открывалось уже запущеное мое приложение ! у меня есть несколько примеров но они не совсем меня устраивают ! И подскажите обязательно ли для этого нужно знать название программы !и если его изменить получиться ли исключить запуск второй копии !
И тут же еще один вопрос к этой теме ! есть два приложение - первое простое с двумя кнопками (к примеру ) а второе имеет две формы ! и вот нужно что б по нажатию той или иной кнопки открывалось то или иное окно второй программы (уже запущеной) !
Заранее огромное спасибо за помощь ! ))
← →
Eraser © (2005-12-07 00:21) [1]
> Конопелька (07.12.05 00:12)
> Подскажите пожалуйста исключение варианта запуска второй
> копии программы
Создать именованый объект ядра, например мьютекс при старте программы, если объект уже существует, значит копия программы уже запущена.
> у меня есть несколько примеров но они не совсем меня устраивают
чем конкретно?
> обязательно ли для этого нужно знать название программы
не обязательно.
> и вот нужно что б по нажатию той или иной кнопки открывалось
> то или иное окно второй программы (уже запущеной)
легко реализуется через пользовательские сообщения.
см. FindWindow, Send/PostMessage.
← →
Конопелька (2005-12-07 00:26) [2]обьясни пожалуйста как это сделать через Мьютекс !? я с этим не знаком ! и если можна то малеенький наглядный пример !!) ?
← →
Eraser © (2005-12-07 00:35) [3]
> Конопелька (07.12.05 00:26) [2]
В dpr файл проекта вставь перед Application.Initialize
CreateMutex(nil, True, "MyCoolProject");
if GetLastError = ERROR_ALREADY_EXISTS then
begin
MessageBox(0, PChar("Config window already EXISTS!"), SApplicationName, MB_ICONERROR);
Halt;
end;
← →
Alexander Panov © (2005-12-07 01:07) [4]
> легко реализуется через пользовательские сообщения.
Совсем даже не легко.
← →
gdaujk © (2005-12-07 09:12) [5]Eraser © (07.12.05 00:35) [3]
Удобнее для пользователя будет програмное переключение на первый экземпляр:var
UniqueMes: Integer;
const
UNIQUE_APP_STR = "MyCoolProject";
...
UniqueMes := RegisterWindowMessage(UNIQUE_APP_STR);
hMutex := CreateMutex(nil, False, UNIQUE_APP_STR);
if GetLastError = ERROR_ALREADY_EXISTS then
begin
PostMessage(HWND_BROADCAST, UniqueMes, 0, 0);
Exit;
end;
...
и после ловить сообщение с Msg = UniqueMes. При получении показать себя пользователю.
← →
Alexander Panov © (2005-12-07 09:32) [6]
> При получении показать себя пользователю.
Думаю, что как раз этот момент и будет самым сложным;)
← →
Eraser © (2005-12-07 11:31) [7]
> Alexander Panov © (07.12.05 01:07) [4]
Ну эт почему же? :)
2-3 строки + обработка сообщения, imho.
← →
gdaujk © (2005-12-07 11:33) [8]>Alexander Panov © (07.12.05 09:32) [6]
>Думаю, что как раз этот момент и будет самым сложным;)
procedure ForceForegroundWindow(MainWnd: HWND);
var
fPID, cPID: DWORD;
begin
fPID := GetWindowThreadProcessId(GetForegroundWindow, nil);
cPID := GetWindowThreadProcessId(MainWnd, nil);
AttachThreadInput(fPID, cPID, True);
ShowWindow(MainWnd, SW_SHOW);
SetForegroundWindow(MainWnd);
AttachThreadInput(fPID, cPID, False);
end;
PS: сабж был уже много раз. Можно было и поискать...
← →
Alexander Panov © (2005-12-07 12:10) [9]
> gdaujk © (07.12.05 11:33) [8]
Приведенного кода недостаточно для правильного восстановления приложения.
> PS: сабж был уже много раз. Можно было и поискать...
Поэтому высказывание мимо кассы.
← →
Alexander Panov © (2005-12-07 12:17) [10]
> PS: сабж был уже много раз. Можно было и поискать...
Что ж ты сам не поискал правильный ответ?
Например, вот -
http://forum.sources.ru/index.php?showtopic=123826&view=showall
← →
gdaujk © (2005-12-07 13:15) [11]Удалено модератором
← →
Alexander Panov © (2005-12-07 13:46) [12]Удалено модератором
← →
gdaujk © (2005-12-07 14:58) [13]>Alexander Panov © (07.12.05 13:46) [12]
>Прочитай внимательно...
Почитал и понял, что основные ограничения SetForegroundWindow накладываются в Win98/Me, и избавится от оных предлагается SystemParametersInfo. Но я чтитал внимательно и сабж, в котором автором тёмно-серым по светло-серому указаны: NT4, Win2k, WinXP. Вопрос почему-то не "отпадает сам собой". Может я недостаточно внимательно читал???
>В следующий раз выбирай выражения
И какое, по вашему, выражение в контексте фразы: "Желательно аргументировать свою точку зрения, иначе можно прослыть ..." - нужно было употребить?
PS: приведите хоть один пример (ситуацию), в котором при повторном запуске приложения в NT4, Win2k, WinXP вариант [8] "недостаточен для правильного восстановления приложения".
← →
Alexander Panov © (2005-12-07 15:01) [14]gdaujk © (07.12.05 14:58) [13]
PS: приведите хоть один пример (ситуацию), в котором при повторном запуске приложения в NT4, Win2k, WinXP вариант [8] "недостаточен для правильного восстановления приложения".
В MSDN ведь написано ясно:
В случае, если пользователь работает с другим приложением, окно не будет выдвинуто на передний план.
Для этого нужно воспользоватьсяSystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
И т.д.
В W2000 и XP именно так и ведет себя функция SetForegroundWindow и иже с ней - прочто начинает мигать кнопка на панели задач, окно же на передний план не появляется.
← →
Alexander Panov © (2005-12-07 15:02) [15]gdaujk © (07.12.05 14:58) [13]
Почитал и понял, что основные ограничения SetForegroundWindow накладываются в Win98/Me
В W2000 и XP ситуация намного хуже.
← →
gdaujk © (2005-12-07 15:09) [16]Alexander Panov © (07.12.05 15:01) [14]
окно же на передний план не появляется
То есть вы хотите сказать, что при выполнении кода [8] окно на передний план не выходит?
PS: код [8] направлен именно на перенесение окна на передний план, а не на мигание...
← →
gdaujk © (2005-12-07 15:12) [17]>В MSDN ведь написано ясно:
However, on Microsoft Windows 98 and Windows Millennium Edition (Windows Me), if a nonforeground thread calls SetForegroundWindow and passes the handle of a window that was not created by the calling thread, the window is not flashed on the taskbar. To have SetForegroundWindow behave the same as it did on Windows 95 and Microsoft Windows NT 4.0, change the foreground lock timeout value when the application is installed. This can be done from the setup or installation application with the following function call:
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
← →
Alexander Panov © (2005-12-07 15:14) [18]gdaujk © (07.12.05 15:09) [16]
То есть вы хотите сказать, что при выполнении кода [8] окно на передний план не выходит?
Именно.
Вот код:class procedure TDummy.RestoreApp(Sender: TObject);
var
hWnd, hCurWnd, dwThreadID, dwCurThreadID: THandle;
OldTimeOut: Cardinal;
AResult: Boolean;
begin
hWnd := Application.Handle;
SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, @OldTimeOut, 0);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Pointer(0), 0);
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
hCurWnd := GetForegroundWindow;
AResult := False;
while not AResult do
begin
dwThreadID := GetCurrentThreadId;
dwCurThreadID := GetWindowThreadProcessId(hCurWnd);
AttachThreadInput(dwThreadID, dwCurThreadID, True);
AResult := SetForegroundWindow(hWnd);
AttachThreadInput(dwThreadID, dwCurThreadID, False);
end;
SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Pointer(OldTimeOut), 0);
Application.Restore;
end;
(c) Rouse_ & y-soft
← →
Alexander Panov © (2005-12-07 15:15) [19]gdaujk © (07.12.05 15:12) [17]
В W98 и WindowsNT как раз нет проблем с этим.
В ME не знаю - не использовал.
← →
gdaujk © (2005-12-07 15:24) [20]>Alexander Panov © (07.12.05 15:14) [18]
>Именно.
А у меня, на XP, работает. С чего бы это? Может пришлёте код неработающего приложения?
>Alexander Panov © (07.12.05 15:15) [19]
В W98 ... как раз нет проблем с этим.
А как тогда объяснить gdaujk © (07.12.05 15:12) [17]?
← →
Конопелька (2005-12-07 16:04) [21]Я конечно извиняюсь !! Но я немного непонял наверно ! Вот я сделал так вроде работает ! Но вот в чем проблема ! Один раз он восстанавливает программу ! Но когда второй раз повторно запускаешь программу то он неможет ее закрыть и обработчики событий OnCloseQuery тож неработает и на панели задач она не появляеться !
Вот код программы:program server;
uses
Forms,Windows,ShellAPI,
mainform in "mainform.pas" {mainform1};
{$R *.res}
procedure ForceForegroundWindow(MainWnd: HWND);
var
fPID, cPID: DWORD;
begin
fPID := GetWindowThreadProcessId(GetForegroundWindow, nil);
cPID := GetWindowThreadProcessId(MainWnd, nil);
AttachThreadInput(fPID, cPID, True);
ShowWindow(MainWnd, SW_SHOW);
SetForegroundWindow(MainWnd);
AttachThreadInput(fPID, cPID, False);
end;
var Handle:longint;
begin
Handle:=FindWindow("Tmainform1",nil);
if handle=0 then
begin
Application.Initialize;
Application.CreateForm(Tmainform1, mainform1);
Application.Run;
end
else
begin
ForceForegroundWindow(handle);
end;
end.
Что я сделал неправильно ! ??
← →
Virgo_Style © (2005-12-07 16:08) [22]offtop: ну зачем же столько "!" ?
← →
Alexander Panov © (2005-12-07 16:12) [23]gdaujk © (07.12.05 15:24) [20]
А у меня, на XP, работает. С чего бы это? Может пришлёте код неработающего приложения?
С того, что если работает у тебя в конкретной ситуации, еще не значит, что работать будет везде.
← →
Alexander Panov © (2005-12-07 16:13) [24]gdaujk © (07.12.05 15:24) [20]
Может пришлёте код неработающего приложения?
Откуда я его возьму?
← →
Alexander Panov © (2005-12-07 16:13) [25]gdaujk © (07.12.05 15:24) [20]
Кстати, топик по ссылке прочитал? Там есть замечания и некоторые ссылки на материалы.
← →
gdaujk © (2005-12-07 16:49) [26]Конопелька (07.12.05 16:04) [21]
Ты не правильно делаешь. Правильно попожже напишу. Вообще, роблемма в том, что в VCL приложениях TForm - дочерняя форма. Я же взял код из своей программы, написанной целиком на WinAPI, там всё проще. Сейчас сделаю правильно, выкину сюды...
Alexander Panov © (07.12.05 16:12) [23]
Интересный довод :-). Ващ код в ДОС тоже робить не будет :-))) Приведите конкретный пример...
По топику пробежался глазами... Но SystemParametersInfo - только для Win98/ME.
PS: автор, вы предполагаете работу вашей программы под Win98/ME?
← →
Leonid Troyanovsky © (2005-12-07 17:01) [27]
> gdaujk © (07.12.05 16:49) [26]
> Интересный довод :-). Ващ код в ДОС тоже робить не будет
> :-))) Приведите конкретный пример...
Нет смысла приводить какой-либо пример, бо вместо того, чтобы
неактивный процесс вытаскивал себя в foreground в нарушение
политики MS, можно было законно сделать SetForegroundWindow
из своего foreground приложения.
А всем этим хакерским штучкам судьба жить до очередного SP.
Причем, чем более разрекламированный способ, тем меньше ему жить.
Т.е., если я знаю, как обойти оное ограничение, я ни с кем не поделюсь,
бо (1) нефик идти поперек MS, (2) вдруг мне самому приcпичит поперек.
--
Regards, LVT.
← →
Rouse_ © (2005-12-07 17:53) [28]Хм, код который привел > Alexander Panov © (07.12.05 15:14) [18] вполне документирован в MSDN. Не вижу тут никаких "хакерских штучек" :)
на всякий случай приведу полный вариант примера:
DPR:program Project1;
uses
Windows,
Forms,
Unit1 in "Unit1.pas" {Form1};
{$R *.res}
var
RestoreOldInstance: Cardinal;
begin
CreateMutex(nil, True, "{C68C1DD9-2CB0-4B2F-9A6A-29F4ADE5707D}");
if GetLastError = ERROR_ALREADY_EXISTS then
begin
if MessageBox(0,
"Запуск второй копии приложения запрещен, активизировать предыдущую копию?",
"Ошибка", MB_YESNO + MB_ICONERROR + MB_DEFBUTTON1) = ID_YES then
begin
RestoreOldInstance :=
RegisterWindowMessage("{FC9D27F6-D173-4CF6-8A9A-3A2197C72390}");
PostMessage(HWND_BROADCAST, RestoreOldInstance, 0, 0); // y-soft
end;
Exit;
end;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Форма:unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
RestoreOldInstance: Cardinal;
function ApplicationMessage(var Message: TMessage): Boolean;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function TForm1.ApplicationMessage(var Message: TMessage): Boolean;
var
hWnd, hCurWnd, dwThreadID, dwCurThreadID: THandle;
OldTimeOut: Cardinal;
AResult: Boolean;
begin
Result := False;
if Message.Msg = RestoreOldInstance then
begin
Application.Restore; // y-soft
hWnd := Application.Handle;
SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, @OldTimeOut, 0);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Pointer(0), 0);
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
hCurWnd := GetForegroundWindow;
AResult := False;
while not AResult do
begin
dwThreadID := GetCurrentThreadId;
dwCurThreadID := GetWindowThreadProcessId(hCurWnd);
AttachThreadInput(dwThreadID, dwCurThreadID, True);
AResult := SetForegroundWindow(hWnd);
AttachThreadInput(dwThreadID, dwCurThreadID, False);
end;
SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Pointer(OldTimeOut), 0);
end;
inherited;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
RestoreOldInstance :=
RegisterWindowMessage("{FC9D27F6-D173-4CF6-8A9A-3A2197C72390}");
Application.HookMainWindow(ApplicationMessage);
end;
end.
← →
gdaujk © (2005-12-07 18:02) [29]Leonid Troyanovsky © (07.12.05 17:01) [27]
А всем этим хакерским штучкам
Почему хакерским? По-моему, вопрос возникает из-за того, что автор, как и многие другие разработчики, считает, что в ситуации, когда пользователь запускает вторую копию, а должна быть только одна, логично было бы показать ему первый экземпляр, ведь пользователь, в общем-то, этого и хочет. А политики MS, как и пути господни, неисповедима :-)))
Обещанный код
Основан на материалах книги: "Delphi 5: руководство разработчика" Стива Тейксейра и Ксавье Пачеко.
Просто присоедините нижеописанный модуль к программе. Больше ничего делать не надо :-)unit gdaMultInst;
interface
implementation
uses Forms, Windows;
var
WProc: TFNWndProc;
hMutex: THandle;
MIError: Integer;
UniqueMes: Integer;
const
MI_ERROR_NONE = 0;
MI_ERROR_FAILSUBCLASS = 1;
MI_ERROR_CREATINGMUTEX = 2;
UNIQUE_APP_STR = "MyCoolProject";
procedure ForceForegroundWindow(MainWnd: HWND);
var
fPID, cPID: DWORD;
begin
fPID := GetWindowThreadProcessId(GetForegroundWindow, nil);
cPID := GetWindowThreadProcessId(MainWnd, nil);
AttachThreadInput(fPID, cPID, True);
ShowWindow(MainWnd, SW_SHOWNORMAL);
SetForegroundWindow(MainWnd);
AttachThreadInput(fPID, cPID, False);
end;
function NewWndProc(Handle: HWND; Msg: Integer; wParam, lParam: Longint): Longint; stdcall;
begin
Result := 0;
if Msg = UniqueMes
then ForceForegroundWindow(Application.Handle)
else
Result := CallWindowProc(WProc, Handle, Msg, wParam, lParam);
end;
procedure SubClassAplication;
begin
WProc := TFNWndProc(SetWindowLong(Application.Handle, GWL_WNDPROC, Longint(@NewWndProc)));
if WProc = nil
then MIError := MIError or MI_ERROR_FAILSUBCLASS;
end;
procedure DoFirstInstance();
begin
hMutex := CreateMutex(nil, False, UNIQUE_APP_STR);
if hMutex = 0
then MIError := MIError or MI_ERROR_CREATINGMUTEX;
end;
procedure BroadcastFocusMessage();
var
BSMRecipients: DWORD;
begin
Application.ShowMainForm := False;
BSMRecipients := BSM_APPLICATIONS;
BroadcastSystemMessage(BSF_IGNORECURRENTTASK or BSF_POSTMESSAGE,
@BSMRecipients,
UniqueMes,
0, 0);
end;
procedure InitInstance;
begin
SubClassAplication;
hMutex := CreateMutex(nil, False, UNIQUE_APP_STR);
if GetLastError = ERROR_ALREADY_EXISTS then
begin
BroadcastFocusMessage;
Application.Terminate;
end;
end;
initialization
UniqueMes := RegisterWindowMessage(UNIQUE_APP_STR);
InitInstance;
finalization
if WProc <> nil
then SetWindowLong(Application.Handle, GWL_WNDPROC, Longint(WProc));
if hMutex <> 0 then CloseHandle(hMutex);
end.
PS: писал второпях, так что скорее всего есть ошибки...
← →
Leonid Troyanovsky © (2005-12-07 18:07) [30]
> Rouse_ © (07.12.05 17:53) [28]
> Хм, код который привел > Alexander Panov © (07.12.05 15:
> 14) [18] вполне документирован в MSDN. Не вижу тут никаких
> "хакерских штучек" :)
Хакерские штучки - это разнообразные варианты ForceForeground.
Хотя, фокусы SystemParametersInfo ничем не лучше.
Еще раз повторю, вместо того, чтобы законно сделать из своего
foreground приложения SetForegroundWindow, левой ногой тянемся
к правому уху.
И еще рефрен: чего все привязались к мьютексам, семафор -то
гораздо полезней, он хоть 4 байтовое число хранить может.
--
Regards, LVT.
← →
Leonid Troyanovsky © (2005-12-07 18:12) [31]
> gdaujk © (07.12.05 18:02) [29]
Xavi, конечно, уважаемый guy, но этот код очень далек от совершенства.
Особенно мне не нравятся всякие бродкасты.
--
Regards, LVT.
← →
Игорь Шевченко © (2005-12-07 18:27) [32]А вот народу нифига непонятно, почему, собстна нельзя просто вызвать SetForegroundWindow ?
← →
gdaujk © (2005-12-07 18:30) [33]Leonid Troyanovsky © (07.12.05 18:12) [31]
Особенно мне не нравятся всякие бродкасты.
Чем? В Win2k оные никаких проблем не создают...
PS: а что ишшо не нравится? Я поправлю...
← →
Eraser © (2005-12-07 18:33) [34]
> Игорь Шевченко ©
Ну да, по логике, после закрытия текущего окна, активным станет то, для которого вызвана SetForegroundWindow.
← →
Leonid Troyanovsky © (2005-12-07 18:44) [35]
> gdaujk © (07.12.05 18:30) [33]
> PS: а что ишшо не нравится? Я поправлю...
+ Mutex, +ForceForeground и др.
Т.е., берешь именованный FileMapping, и хранишь там нужный хендл окна.
Если маппинг с таким именем уже есть, то читается этот хендл и делается:
h := GetWindowLong(ahwnd, GWL_HWNDPARENT); // окно приложения
if IsIconic(h) then
ShowWindow(h, SW_RESTORE);
SetForegroundWindow(h);
SendMessage(h, WM_COPYDATA, ..);
Halt;
И все, собс-но.
--
Regards, LVT.
← →
Leonid Troyanovsky © (2005-12-07 18:48) [36]
> Eraser © (07.12.05 18:33) [34]
> Ну да, по логике, после закрытия текущего окна,
Это можно сделать до создания окна.
А запущенное юзером, скажем, из экплорера или из комстроки
вторая копия будет foreground (по определению).
--
Regards, LVT.
← →
gdaujk © (2005-12-07 18:52) [37]Leonid Troyanovsky © (07.12.05 18:44) [35]
А говорили: "... ни с кем не поделюсь" :-) Интересный вариант, надо попробовать.
Но в общем-то, на сколько я понял, вам не нравится метод мой, а не его реализация?
PS: А можно ишшо про приемущества семафоров?
← →
Alexander Panov © (2005-12-07 18:57) [38]Игорь Шевченко © (07.12.05 18:27) [32]
почему, собстна нельзя просто вызвать SetForegroundWindow ?
Foreground and Background Windows
Each process can have multiple threads of execution, and each thread can create windows. The thread that created the window with which the user is currently working is called the foreground thread, and the window is called the foreground window. All other threads are background threads, and the windows created by background threads are called background windows.
Each thread has a priority level that determines the amount of CPU time the thread receives. Although an application can set the priority level of its threads, normally the foreground thread has a slightly higher priority level than the background threads. Because it has a higher priority, the foreground thread receives more CPU time than the background threads. The foreground thread has a normal base priority of 9; a background thread has a normal base priority of 7.
The user sets the foreground window by clicking a window, or by using the ALT+TAB or ALT+ESC key combination. To retrieve a handle to the foreground window, use the GetForegroundWindow function. To check if your application window is the foreground window, compare the handle returned by GetForegroundWindow to that of your application window.
An application sets the foreground window by using the SetForegroundWindow function.
Windows NT 4.0 and earlier, Windows 95: If the new foreground window is a top-level window, the system activates it; otherwise, it activates the associated top-level window.
Windows 98/Me/2000/XP: The system restricts which processes can set the foreground window. A process can set the foreground window only if one of the following conditions is true:
The process is the foreground process.
The process was started by the foreground process.
The process received the last input event.
There is no foreground process.
The foreground process is being debugged.
The foreground is not locked (see LockSetForegroundWindow).
The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
Windows 2000/XP: No menus are active.
Windows 2000/XP: A process that can set the foreground window can enable another process to set the foreground window by calling the AllowSetForegroundWindow function, or by calling the BroadcastSystemMessage function with the BSF_ALLOWSFW flag. The foreground process can disable calls to SetForegroundWindow by calling the LockSetForegroundWindow function.
← →
Alexander Panov © (2005-12-07 19:00) [39]Leonid Troyanovsky © (07.12.05 18:44) [35]
И все, собс-но.
С учетом [38] вообще-то не все;)
← →
gdaujk © (2005-12-07 19:01) [40]Leonid Troyanovsky © (07.12.05 18:48) [36]
Приемущества семафора понял, объяснять не надо.
PS: автор врядли сам справится что с семафорами, что с мутексами, что с маппингами, так что [29] для него сасое то. А я щас семафоры-то наверное попробую...
← →
Leonid Troyanovsky © (2005-12-07 19:07) [41]
> Alexander Panov © (07.12.05 19:00) [39]
> С учетом [38] вообще-то не все;)
Если уж его залочили, то, видимо, не без для этого оснований.
Т.е., в этом случае он и рассчитывал на лишь поморгать.
--
Regards, LVT.
← →
Alexander Panov © (2005-12-07 19:10) [42]Leonid Troyanovsky © (07.12.05 19:07) [41]
Если уж его залочили, то, видимо, не без для этого оснований.
Захватывается он системой, и в MSDN описано, для чего.
У нас больше оснований снять блокировку.
← →
Leonid Troyanovsky © (2005-12-07 19:24) [43]
> Alexander Panov © (07.12.05 19:10) [42]
> Захватывается он системой, и в MSDN описано, для чего.
Это немного не то.
Зато я нашел подтверждение своей мысли,
в описалове к AllowSetForegroundWindow:
Windows 95/98/Me: This function is not implemented. Therefore, processes must cooperate to manage the foreground window. For example, an application may wish to support only one instance. When the second instance starts up, it should detect the previous instance and call SetForegroundWindow on the window of the previous instance. It should not post a message to the window of the previous instance asking it to call SetForegroundWindow on itself, because the previous instance will not necessarily have permission to call SetForegroundWindow.
--
Regards, LVT.
← →
gdaujk © (2005-12-07 19:36) [44]Leonid Troyanovsky © (07.12.05 18:48) [36]
Это конечно полный offtop, но возникла проблемма: где взять констатны SEMAPHORE_ALL_ACCESS, SEMAPHORE_MODIFY_STATE, и т. п. для OpenSemaphore? У меня в Windows.pas их нет.
PS: Можно хотябы их значения...
← →
Джо © (2005-12-07 19:38) [45]
SEMAPHORE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $3);
SEMAPHORE_MODIFY_STATE = $0002;
Из windows.pas для D2005. Могу выслать или уточни "и т.п.".
← →
Alexander Panov © (2005-12-07 19:44) [46]
SEMAPHORE_ALL_ACCESS = $01f0003
SEMAPHORE_MODIFY_STATE = 2
SYNCHRONIZE = $0100000
← →
gdaujk © (2005-12-07 20:10) [47]Джо © (07.12.05 19:38) [45]
SEMAPHORE_MODIFY_STATE уже сам догадался :-) Но спасибо.
Alexander Panov © (07.12.05 19:44) [46]
Спасибо.
← →
gdaujk © (2005-12-07 21:01) [48]А с семафорами точно намного лучше, вроде полная независимость от версии Windows!!! Хотя пробовал только на XP.
Выкладывать не стану, кто хочет - сам напишет. А написать очень советую...
PS: Leonid Troyanovsky, спасибо, что просвятили дурака...
← →
Джо © (2005-12-07 21:04) [49]
> [48] gdaujk © (07.12.05 21:01)
Так вроде и CreateMutex независим от версии Windows?
← →
gdaujk © (2005-12-07 21:13) [50]Джо © (07.12.05 21:04) [49]
Только с семафорами всё равно намного лучше.
← →
Джо © (2005-12-07 21:14) [51]
> [50] gdaujk © (07.12.05 21:13)
> Только с семафорами всё равно намного лучше.
Попробую поверить на слово :)
← →
gdaujk © (2005-12-07 22:47) [52]Leonid Troyanovsky © (07.12.05 18:44) [35]
С маппингами тоже сделал, в принципе оптимальный вариант. А кусок
if IsIconic(h) then
ShowWindow(h, SW_RESTORE);
SetForegroundWindow(h);
под Win98/ME точно будет работать?
PS: ЗачемSendMessage(h, WM_COPYDATA, ..);
← →
Eraser © (2005-12-07 23:40) [53]
> gdaujk © (07.12.05 22:47) [52]
> PS: Зачем
>
> SendMessage(h, WM_COPYDATA, ..);
Чтобы, например, передать параметр командной строки в существующую копию программы.
← →
gdaujk © (2005-12-08 06:46) [54]>Eraser © (07.12.05 23:40) [53]
Вобщем-то да, я об этом не подумал.
>gdaujk © (07.12.05 22:47) [52]
>А кусок ... под Win98/ME точно будет работать?
С учётом Leonid Troyanovsky © (07.12.05 18:48) [36] вопрос снимается, ибо "The process was started by the foreground process" => "A process can set the foreground window"...
← →
Leonid Troyanovsky © (2005-12-08 09:12) [55]
> gdaujk © (07.12.05 21:01) [48]
> А с семафорами точно намного лучше, вроде полная независимость
> от версии Windows!!! Хотя пробовал только на XP.
>
> Выкладывать не стану, кто хочет - сам напишет. А написать
> очень советую...
С семафором я пошутил.
Дело в том, что параметр там LONG >= 0.
А хендлы, скажем, в 98, могут иметь значения и больше $7FFFFFFF.
Насчет XP, w2k не уверен, но и про гарантии ничего не слышал.
Кроме того, семафор неудобен тем, что обращение к нему
придется синхронизировать тем же мьютексом, для того,
чтобы избежать разрыва между wait & release.
Ну, а вариант с маппингом я бы советовал выложить.
Во-первых, взгляд со стороны в нашем деле не лишний.
А, во-вторых, это, IMHO, довольно частый вопрос.
--
Regards, LVT.
← →
Leonid Troyanovsky © (2005-12-08 09:15) [56]
> gdaujk © (07.12.05 18:52) [37]
> А говорили: "... ни с кем не поделюсь" :-)
Я имел ввиду только реализации ForceForeground.
И даже обосновал :)
--
Regards, LVT.
← →
Leonid Troyanovsky © (2005-12-08 09:18) [57]
> gdaujk © (07.12.05 22:47) [52]
> PS: Зачем
> SendMessage(h, WM_COPYDATA, ..);
Кста, я хотел написать ahwnd, т.е., то, что сохранялось в мапинге.
Ну и SetForeground, видимо, ему же.
--
Regards, LVT.
← →
Defunct © (2005-12-08 10:14) [58]Извините если повторю чей-то ответ, всю ветку не читал.
> Подскажите пожалуйста исключение варианта запуска второй копии программы
"Механизм прост как Мир" (C) Ордынская
Регистрируется сообщение с уникальной идентификационной строкой, и отправляется всем окнам. Если в системе присутствует Ваша программа, то она ловит это сообщение и шлет ответ, мы получаем этот ответ, шлем назад конкретному окну требование "всплыть", а сами потихому уходим (Application.Terminate либо Halt). Пример:unit unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
const
WM_DONTINITIALIZE = WM_USER + 0;
WM_BRINGTOFRONT = WM_USER + 1;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
protected
procedure WndProc(var Message: TMessage);override;
end;
implementation
{$R *.dfm}
var
STARTUP_MSG : Integer;
CanInitialize : boolean;
procedure TForm1.FormCreate(Sender: TObject);
begin
CanInitialize := true;
STARTUP_MSG := RegisterWindowMessage("SAT_SERVER StartUP message");
if STARTUP_MSG = 0 then
ShowMessage("Не удалось зарегистрировать сообщение"+#13+#10+
"для пресечения повторного запуска программы");
SendMessage(HWND_BROADCAST, STARTUP_MSG, Handle, 0);
if CanInitialize then
begin
ShowMEssage("запуск программы возможен");
//Initializing
end
else
begin
ShowMessage("Обнаружена ранее запущенная копия программы, фокус передан ей");
Application.Terminate;
end;
end;
procedure TForm1.WndProc(var Message: TMessage);
begin
if Handle <> Message.WParam then
if Message.Msg = STARTUP_MSG then
SendMessage(Message.WParam , WM_DONTINITIALIZE, Handle, 0)
else
case Message.MSG of
WM_DONTINITIALIZE:
begin
CanInitialize := False;
SendMessage( Message.WParam, WM_BRINGTOFRONT, Handle, 0);
end;
WM_BRINGTOFRONT:
begin
Show;
Application.BringToFront;
end;
end;
inherited WndProc(Message);
end;
end.
← →
Defunct © (2005-12-08 10:24) [59]Defunct © (08.12.05 10:14) [58]
Пример можно значительно сократить, выбросив переменную CanInitialize и все что с ней связано, если Application.Terminate вставить непосредственно в обработчик WM_DONTINITIALIZE.
← →
Leonid Troyanovsky © (2005-12-08 10:33) [60]
> Defunct © (08.12.05 10:14) [58]
> "Механизм прост как Мир" (C) Ордынская
Простота мира зависит от простоты наблюдателя.
Скажем, слабый антропный принцип (в моем упрощении).
> Регистрируется сообщение с уникальной идентификационной
> строкой, и отправляется всем окнам. Если в системе присутствует
> Ваша программа, то она ловит это сообщение и шлет
Ну, видимо, почитать предыдущее следовало бы.
Во-первых, ничего регистрировать не надо.
Во-вторых, никаких бродкастов.
В-третьих, на сайте Анатолия Подгорецкого есть фак fido7.delphi,
в котором все подробно разложено, какое д.б. окно, как его
искать, как послать WM_COPYDATA и т.д., все в одном юните.
Q-142: Как избежать повторного запуска моего приложения?
--
Regards, LVT.
← →
Defunct © (2005-12-08 10:50) [61]Leonid Troyanovsky © (08.12.05 10:33) [60]
> Во-первых, ничего регистрировать не надо.
> Во-вторых, никаких бродкастов.
это во-первых на любителя, а во-вторых зависит от конкретной задачи..
> В-третьих, на сайте Анатолия Подгорецкого есть фак fido7.delphi,
в котором все подробно разложено, какое д.б. окно, как его
искать, как послать WM_COPYDATA и т.д., все в одном юните.
Этот FAQ я читал, очень полезный и занимательный (у меня на него ссылка на рабочем столе лежит), однако, для решения второй стороны сабжевого вопроса - взаимодействие между двумя различными приложениями, мой пример очень даже может пригодиться.
Вам тоже Regards
← →
Владислав © (2005-12-08 11:21) [62]
> Игорь Шевченко © (07.12.05 18:27) [32]
> А вот народу нифига непонятно, почему, собстна нельзя просто
> вызвать SetForegroundWindow ?
После нескольких часов напряженной работы я устаю и становлюсь раздражительным. Поэтому мне лучше не садиться за управление танком, иначе я бы с удовольствием переехал бы несколько раз того программиста, который устанавливает фокус ввода на окошко своей любимой и глубокоуважаемой им программы в то время, когда я работаю с другой, не менее любимой мной, программой.
И вообще, господа, если вы хотите привлечь мое внимание, совсем не обязательно бить меня кувалдой по голове. Достаточно будет назвать мое имя, ну или тронуть меня за плечо, если я в глубокой задумчивости.
К чему это все?.. Моргания вполне бы хватило...
← →
Leonid Troyanovsky © (2005-12-08 11:28) [63]
> Defunct © (08.12.05 10:50) [61]
> > Во-вторых, никаких бродкастов.
> это во-первых на любителя, а во-вторых зависит от конкретной
> задачи..
Я и высказался о конкретно этой задаче.
Особенно в конкретном исполнении.
--
Regards, LVT.
← →
Defunct © (2005-12-08 11:35) [64]Владислав © (08.12.05 11:21) [62]
С бОльшим удовольствием можно переехать того программиста, чья программа при запуске не всплывет, а либо молчит либо просто "моргает в таскбаре".
← →
Leonid Troyanovsky © (2005-12-08 11:36) [65]
> Владислав © (08.12.05 11:21) [62]
> > А вот народу нифига непонятно, почему, собстна нельзя
> просто
> > вызвать SetForegroundWindow ?
> После нескольких часов напряженной работы я устаю и становлюсь
> раздражительным.
Надеюсь, пару минут у нас еще есть? ;)
Позволю себе заметить, что в контексте данного обсуждения,
передача фокуса другому приложению не является преступным,
бо начинается сие деянием юзера по запуску приложения.
Ну, а мы, вполне правы в том, что если юзер хочет приложения,
причем, ожидая его foreground, то он получит его (пусть даже это
будет первый экземпляр, тихо сидевший в бекграунде).
Я бы например, на подмигивание в таком случае просто бы обиделся.
--
Regards, LVT.
← →
Defunct © (2005-12-08 11:56) [66]Leonid Troyanovsky © (08.12.05 11:28) [63]
Поясните пожалуйста Вашу точку зрения, а именно чем связка RegisterMessage+broadcast будет хуже связки "FindGUID(FindWindow+GetProp/SetProp)? Хотелось бы услышать обоснованный ответ.
Пример с мьютексом в FAQ-Q142 вообще imho недостоин внимания, т.к. возможны сбои в работе из-за проверки по "заголовку программы".
← →
Владислав © (2005-12-08 12:02) [67]
> Leonid Troyanovsky © (08.12.05 11:36) [65]
Да живите, чего уж там :) Я танком управлять не умею :о)
Останусь при своем, все таки...
← →
Leonid Troyanovsky © (2005-12-08 12:18) [68]
> RegisterMessage+broadcast будет хуже связки "FindGUID
> Хотелось бы услышать обоснованный ответ.
В общем: SendMessage vs SendMessageTimeout.
В частности: в приложениях Delphi даже таймеры имеют top-level окно.
И каждое должно ответить, т.е., с переключением контекста.
Т.е., FindWindow лучше, хотя, возможно, еще лучше - EnumWindows.
--
Regards, LVT.
← →
Leonid Troyanovsky © (2005-12-08 12:27) [69]
> Defunct © (08.12.05 11:56) [66]
> Пример с мьютексом в FAQ-Q142 вообще imho недостоин внимания,
> т.к. возможны сбои в работе из-за проверки по "заголовку
> программы".
Он вполне достоин.
Просто выбор имени оставлен заинтересованным лицам.
Бо, пусть каждый решает оную проблему сам.
--
Regards, LVT.
← →
Plotnick (2005-12-08 13:07) [70]Также, извиняюсь, если повтор. Просто мне кажется, что у меня написано покороче.
В dpr проекта.
var
g_hAppMutex: THandle;
function OneInstance: boolean;
begin
g_hAppMutex:=CreateMutex(nil,false,PChar("MyCoolProga"+IntToStr(GetDesktopWindow)));
Result:=(WaitForSingleObject(g_hAppMutex,0)<>WAIT_TIMEOUT);
end;
begin
if OneInstance then begin
// Здесь код по созданию окон и запуска приложения
end;
end.
Что касается того, можно ли вытащить приложение на передний экран, то в MSDN я где-то читал, что этого сделать нельзя. То есть в 2000 и ХР приложение будет мигать в таскбаре, но на передний план не выйдет.
Однако есть способ обойти эту проблему - одно приложение может вытащить другое приложение на передний план. Для этого создается утиля со следующим кодом:
var
PrevInstHandle: THandle;
dw: DWord;
hCurrWnd: HWnd;
iMyTID,iCurrTID: Integer;
S: String;
c: Integer;
begin
S := ParamStr(1);
val(S,PrevInstHandle,C);
SendMessage(PrevInstHandle, WM_SYSCOMMAND, SC_RESTORE, 0);
SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, @dw, 0);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, nil, 0);
SetForegroundWindow(PrevInsthandle);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Pointer(dw), 0);
hCurrWnd := GetForegroundWindow();
iMyTID := GetCurrentThreadId();
iCurrTID := GetWindowThreadProcessId(hCurrWnd,nil);
AttachThreadInput(iMyTID, iCurrTID, TRUE);
SetForegroundWindow(PrevInsthandle);
AttachThreadInput(iMyTID, iCurrTID, FALSE);
end.
При запуске этой утилиты ей надо в параметрах передать Hanlde гавного окна того приложения, которое надо вытащить на передний план (в строковом виде, ессно). И все. Это работает с гарантией.
ЗЫ. В случае, когда второй экземпляр программы должен поднять первый экземпляр программы и завершить свою работу отдельную утилиту создавать не надо. Это надо только тогда, когда прога должна вытащить саму себя.
← →
Leonid Troyanovsky © (2005-12-08 13:46) [71]
> Plotnick (08.12.05 13:07) [70]
> Также, извиняюсь, если повтор. Просто мне кажется, что у
Читать топик c самого начала.
Вдумчиво, внимательно.
--
Regards, LVT.
← →
gdaujk © (2005-12-08 14:09) [72]Plotnick (08.12.05 13:07) [70]
Просто мне кажется, что у меня написано покороче.
У кого "короче", тот сидит дома и методически наращивает. Помни: размер имеет значение :-)))
PS: кстати, на счёт "политики M$" и обидчивости некоторых юзеров (Владислав © (08.12.05 11:21) [62]). Проанализируйте действия в подобной ситуации Windows Media Player"а (8)...
Страницы: 1 2 вся ветка
Текущий архив: 2006.02.26;
Скачать: CL | DM;
Память: 0.71 MB
Время: 0.045 c