
Последние записи
- Удалить повторы со сложением значений (Microsoft Office Excel)
- Bass регулировка по отдельности левого и правого каналов звука
- Как ускорить замену текста в MEMO?
- Вывод картинки (текстуры) на OpenGL 3.3 и Qt C++ с плавающем диапазоном координат по оси X
- Поиск ячеек определенного цвета (Microsoft Office Excel)
- Конвертирование кодов в символы (URLDecode в Delphi)
- Рекурсивное удаление файлов из папки (CMD)
- Самый быстрый способ прорисовки на компоненте Image
- Эксперименты с генератором фракталов
- Технология производства чая (белый, зелёный, жёлтый, улун, шен, красный, шу)

27th
Фев
Общение между запущенными копиями своих программ
Posted by Chas under Журнал, Статьи
Рассматривать задачу будем на конкретном примере некоего приложения. Опишем предметную область и постановку задачи: необходимо, чтобы наше приложение, зарегистрировав себя как протокол в системе Windows, при нажатии на ссылку вида testproject:\\xxxxx запустило наше приложение (если оно не запущено) и передало ему параметры ссылки. Если же приложение уже запущено, то необходимо запущенной копии приложения сообщить параметры ссылки.
Павел Добряков
by Квэнди http://kvendi.pp.ru
Что ж, задачу описали, приступим к реализации. Для примера я буду использовать BDS 2006. Создадим новый проект. Для начала нам необходимо зарегистрироваться в реестре, чтобы система воспринимала правильно наши ссылки, поэтому в uses главной формы дописываем модуль registry.
В событии Onactivate() главной формы пишем:
procedure Tfstart.FormActivate(Sender: TObject);
var reg: tregistry;
begin
reg:=tregistry.Create;
reg.RootKey:=HKEY_Classes_Root;
if not(reg.KeyExists(‘testproject’)) then begin
reg.OpenKey(‘testproject’,true);
reg.WriteString(”,’URL:testproject Protocol’);
reg.WriteString(‘URL Protocol’,”);
reg.OpenKey(‘DefaultIcon’,true);
reg.WriteString(”,application.ExeName);
reg.CloseKey;
reg.OpenKey(‘testproject\shell\open\command’,true);
reg.WriteString(”,application.ExeName+’ %1?);
reg.CloseKey;
end;
reg.Free;
end;
Соответственно мы имеем зарегистрированный в системе протокол под названием testproject. Проверить это можно достаточно простым способом: открываем любой браузер и в адресной строке набираем “testproject:\\eee”, после чего запустится ваша программа.
Теперь продолжим. Нам необходимо определять запущена-ли наша программа или нет. Для решения подобной задачи существует множество способов, но я предпочитаю способ с использованием мьютексов*. Не буду сейчас вдавать в подробности описания мьютексов и их использования. Итак, заходим в код нашего проекта и пишем там:
program testproject;
uses
Forms,windows,
Ustart in ‘Ustart.pas’ {fstart};
{$R *.res}
var HM: THandle;
function Check: boolean;
begin
HM := OpenMutex(MUTEX_ALL_ACCESS, false, ‘TestProjectMutex’);
Result := (HM <> 0);
if HM = 0 then HM := CreateMutex(nil, false, ‘TestProjectMutex’);
end;
begin
Application.Initialize;
Application.CreateForm(Tfstart, fstart);
Application.Run;
end.
В результате у нас есть функция, возвращающая true, если копия проекта запущена и false, если это первая копия. Далее нам необходимо понять запущено-ли приложение по ссылке или просто кто-то запустил наш exe-ник. Проверяется достаточно просто: при запуске по ссылке в наше приложение будет передан параметр командной строки, в котором будет сдержаться полностью строка ссылки, поэтому нам необходимо обработать только одно условие:
if (check)and(paramcount>0) then
begin
end;
Итак, что же мы будем делать, если такой процесс уже есть? Нам, соответственно, необходимо каким-то образом сообщить запущенному процессу те параметры, которые нам передали. Отсюда возникает вопрос: нам необходимо знать хэндл нашего уже запущенного приложения. Здесь все подвластно исключительно вашей фантазии, так как сделать это можно сколь угодно множеством способов. Я выберу далеко не лучший, но для примера: будем хранить хэндл в реестре. Для этого модифицируем Onactivate() нашей главной формы:
procedure Tfstart.FormActivate(Sender: TObject);
var reg:tregistry;
begin
reg:= tregistry.Create;
reg.RootKey:=HKEY_Classes_Root;
if not(reg.KeyExists(‘testproject’)) then begin
reg.OpenKey(‘testproject’,true);
reg.WriteString(”,’URL:testproject Protocol’);
reg.WriteString(‘URL Protocol’,”);
reg.OpenKey(‘DefaultIcon’,true);
reg.WriteString(”,application.ExeName);
reg.CloseKey;
reg.OpenKey(‘testproject\shell\open\command’,true);
reg.WriteString(”,application.ExeName+’ %1?);
reg.CloseKey;
end;
reg.RootKey:= HKEY_current_user;
reg.OpenKey(’software\testproject’,true);
reg.WriteInteger(‘handle’,fstart.Handle);
reg.CloseKey;
reg.Free;
end;
Далее добавим обработчик события CloseQuery() нашей формы:
procedure Tfstart.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var reg: tregistry;
begin
reg:=tregistry.Create;
reg.RootKey:=HKEY_current_user;
reg.OpenKey(’software\testproject’, true);
reg.WriteInteger(‘handle’,0);
reg.CloseKey;
reg.Free;
end;
Таким образом, при закрытии программы мы будем обнулять наш хэндл. После чего, проверяем наличие копии уже запущенного приложения. Приведу сразу код:
program testproject;
uses
Forms,windows,registry,sysutils,messages,
Ustart in ‘Ustart.pas’ {fstart};
{$R *.res}
var HM,HForm: THandle;
reg: tregistry;
ParamCmd:TCopyDataStruct;
function Check: boolean;
begin
HM := OpenMutex(MUTEX_ALL_ACCESS, false, ‘TestProjectMutex’);
Result := (HM <> 0);
if HM = 0 then HM := CreateMutex(nil, false, ‘TestProjectMutex’);
end;
begin
if (check)and(paramcount>0) then begin
{Читаем handle запущенного приложения}
reg:= tregistry.Create;
reg.RootKey:=HKEY_current_user;
reg.OpenKey(’software\testproject’,true);
HForm:=reg.ReadInteger(‘handle’);
reg.CloseKey;
reg.Free;
{Составляем структуру данных ParamCmd}
with ParamCmd do begin
dwData := 0;
cbdata:=strlen(pchar(paramstr(1)))+1;
lpData:=pchar(paramstr(1));
end;
{Посылаем сообщение запущеной программе}
SendMessage(HForm, WM_COPYDATA,application.Handle,longint(@ParamCmd));
Exit;
end;
Application.Initialize;
Application.CreateForm(Tfstart, fstart);
Application.Run;
end.
Вот собственно и почти все. Сейчас наше приложение умеет уже обрабатывать полученные данные и отправлять их запущенной копии приложения. Но нам также необходимо, чтобы наша запущенная копия получила эти данные, поэтому дополним код модуля нашей основной формы:
unit Ustart;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,registry, StdCtrls;
type
Tfstart = class(TForm)
Label1: TLabel;
procedure FormActivate(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
protected
procedure Getmessage(var msg: TWMCopyData); message WM_COPYDATA;
private
{ Private declarations }
public
{ Public declarations }
end;
var
fstart: Tfstart;
implementation
{$R *.dfm}
procedure Tfstart.FormActivate(Sender: TObject);
var reg: tregistry;
begin
reg:= tregistry.Create;
reg.RootKey:=HKEY_Classes_Root;
if not(reg.KeyExists(‘testproject’)) then begin
reg.OpenKey(‘testproject’,true);
reg.WriteString(”,’URL:testproject Protocol’);
reg.WriteString(‘URL Protocol’,”);
reg.OpenKey(‘DefaultIcon’,true);
reg.WriteString(”,application.ExeName);
reg.CloseKey;
reg.OpenKey(‘testproject\shell\open\command’,true);
reg.WriteString(”,application.ExeName+’ %1?);
reg.CloseKey;
end;
reg.RootKey:=HKEY_current_user;
reg.OpenKey(’software\testproject’,true);
reg.WriteInteger(‘handle’,fstart.Handle);
reg.CloseKey;
reg.Free;
if paramcount>0 then // Если это первая копия программы,
label1.Caption:=paramstr(1); // то мы можем сразу смело обрабатывать наши параметры
end;
procedure Tfstart.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var reg: tregistry;
begin
reg:= tregistry.Create;
reg.RootKey:=HKEY_current_user;
reg.OpenKey(’software\testproject’,true);
reg.WriteInteger(‘handle’,0);
reg.CloseKey;
reg.Free;
end;
procedure tfstart.Getmessage(var msg: TWMCopyData);
var sText: array[0..99] of Char;
begin
// Преобразуем полученные данные в строку
StrLCopy(sText, Msg.CopyDataStruct.lpData, Msg.CopyDataStruct.cbData);
label1.Caption:=stext;
end;
end.
Послесловие
Вот собственно и все. Достаточно просто проверить. Запустим первую копию нашего приложения, а затем в браузере наберем:
testproject:\\TEST
И увидим, как на нашей запущенной форме появится этот текст. Надеюсь, что эта информация пригодится вам.
Статья из десятого выпуска журнала «ПРОграммист».
Обсудить на форуме — Общение между запущенными копиями своих программ
Похожие статьи

пеллетные котлы

Пеллетный котел Emtas

Наши форумы по программированию:
- Форум Web программирование (веб)
- Delphi форумы
- Форумы C (Си)
- Форум .NET Frameworks (точка нет фреймворки)
- Форум Java (джава)
- Форум низкоуровневое программирование
- Форум VBA (вба)
- Форум OpenGL
- Форум DirectX
- Форум CAD проектирование
- Форум по операционным системам
- Форум Software (Софт)
- Форум Hardware (Компьютерное железо)