2009-03-04 3 views
8

У меня есть приложение-приложение, встроенное в Delphi, которое отлично работает. Он делает именно то, что я хочу, чтобы он делал, и все счастливы. Все нормально, пока я не хочу запускать два (или более) экземпляра этой службы на одной машине. Поскольку имя службы жестко закодировано в программе (через свойство Name службы), я могу установить службу только один раз на любом компьютере. Если я попытаюсь изменить свойство Name во время выполнения, служба не отвечает, если для свойства Name не установлено то же самое, что было установлено во время разработки.Возможно ли установить несколько экземпляров одного и того же приложения-приложения delphi?

Я сделал обходной путь для этого, когда у меня есть весь код, который не взаимодействует напрямую с менеджером управления сервисом, инкапсулированным в отдельные единицы. Затем я пишу отдельный проект Delphi для каждого экземпляра, который я хочу от службы, которая имеет достаточно кода для запуска и начала запуска основного кода.

Этот метод, на мой взгляд, уродлив и, безусловно, неэффективен. Он работает нормально для двух экземпляров, но тогда нам нужен третий и четвертый и ...

Есть ли способ изменить мой код, чтобы у меня был только один проект Delphi, который может устанавливать и запускать себя как несколько экземпляры службы с некоторым простым входом во время выполнения (например, флаг командной строки)?

Или, возможно, более широкий вопрос: есть ли «правильный путь» для достижения цели?

ответ

13

Вы не дали понять, что вы пытались изменить в подклассе TService.

Вы добавили обработчик «BeforeInstall»?

Что-то вроде:

procedure TServiceMain.ServiceLoadInfo(Sender : TObject);// new method, not an override 
begin 
    Name := ParamStr(2); 
    DisplayName := ParamStr(3); 
end; 

procedure TServiceMain.ServiceBeforeInstall(Sender: TService); 
begin 
    ServiceLoadInfo(Self); 
end; 
procedure TServiceMain.ServiceCreate(Sender: TObject); 
begin 
    ServiceLoadInfo(Self); 
end; 

Если вы делаете это регулярно, подкласс TService делать Thie в конструкторе вместо этого.

Вы должны сделать то же самое в программе BeforeUninstall, чтобы указать оба события одним и тем же методом.

C:\>servicename /install MyService "My Service Description" 
+0

Если я это сделаю, служба не запускается, если параметр ParamStr (2) не равен значению, установленному для имени в Инспекторе объектов в среде IDE. Если параметр ParamStr (2) отличается, то при запуске службы он переходит в постоянное состояние «Запуск» и никогда не выполняется. –

+0

Извините, это только часть того, что необходимо. Для этого вам нужно событие OnStart. (Работа с памятью здесь!) –

+0

Я не могу найти этот метод ServiceLoadInfo, который вы используете. Это стандартный метод или просто предложение написать метод, который определяет, какое имя он вызывает в этом случае? –

3

Вы можете создать свой сервис с несколькими потоками внутри, каждый из которых действует как собственная версия/копия услуги. Вы контролируете его с помощью API Service Controller, IIRC.

+0

Я подумал об этом, но казалось, что это было в основном создание дублирующего кода. В функциях служб Windows уже есть встроенный модуль управления потоком. Почему бы не использовать это, а не сворачивать самостоятельно? –

+0

Нет, это не то, что я говорю. В Windows есть код сервисного контроллера, который вы можете использовать для запуска/остановки нескольких потоков. Переместите код службы в TThread, и для каждого экземпляра вашей службы просто запустите другой поток. Надеюсь, лучшее объяснение того, что я намеревался. –

+0

Прошу прощения, я все еще не думаю, что понимаю. Как это отображается на панели управления Services (одна запись/несколько)? Предлагаете ли вы использовать API управления службами в своем коде (например, вызвать ControlService) или просто обрабатывать события (например, ServiceStart и т. Д.)? –

2

Ну да, возможно установить несколько экземпляров одной и той же службы, вам просто нужно динамически изменять имя во время установки (не время выполнения), однако это не делает его желательным. (есть пример кода кода в проекте кода http://www.codeproject.com/KB/dotnet/MultipleInstNetWinService.aspx)

Я бы, однако, склонялся к переосмыслению вашего подхода, сами процессы обслуживания действительно должны быть одноточечными, если вам нужны несколько экземпляров процесса, возможно, ваш сервис должен просто контролировать и управлять несколькими процессами, а не быть процессом.

+0

Спасибо, но я не уверен, что это относится к Delphi. Это то, что я пытался сделать - изменить displayName во время события установки, но затем служба задохнулась, когда она попыталась начать с «неправильного» имени. –

+0

Также, пожалуйста, см. Мой комментарий к ответу Кена ... не делает многопоточный контроллер типа обслуживания, излишне скатывающего меня, когда Windows уже может сделать часть контроллера для меня? –

+0

Следуйте совету Кена. То, что вы пытаетесь сделать, - пример плохого дизайна. Не могли бы вы заставить его работать? Конечно. Тебе следует? Нет, нет, если у вас есть ресурсы, чтобы сделать это правильно (и это не просто одноразовый). – Mick

0

Оберните весь свой код в класс, который наследуется от TThread.

При запуске службы он считывает номер из файла настроек или из реестра и создает это множество экземпляров вашего класса.

Каждый экземпляр запускается независимо.

Чтобы изменить количество запущенных экземпляров, вы можете отключить службу, отредактировать параметр (в файле или реестре) и перезапустить службу.

+0

С такой настройкой предположим, что я запускаю службу с тремя потоками. Могу ли я затем остановить поток 2, оставив потоки 3 и 1 (без написания куча кода, чтобы эффективно воссоздать контроллер службы)? –

+0

С предложением, которое я сделал, да. Ваш основной поток будет обрабатывать запросы для запуска и остановки дочерних потоков; эти дочерние потоки будут теми, кто выполняет фактическую работу. Вы связываетесь с основным потоком службы с помощью API управления сервисом. (Как я упоминал в своем комментарии к вам ниже моего ответа.) –

0

Принятый ответ был очень полезен.

Кода я использовал:

procedure TService1.ServiceAfterInstall(Sender: TService); 
begin 
//http://stackoverflow.com/questions/612587/is-it-possible-to-install-multiple-instances-of-the-same-delphi-service-applicati 
//http://www.c-sharpcorner.com/UploadFile/timosten/DynamicServiceInCSharp11262005062503AM/DynamicServiceInCSharp.aspx?ArticleID=4d5020e4-7317-425c-ab29-5bf37a1db421 
//http://support.microsoft.com/kb/137890 
    SaveRegSetting('\SYSTEM\CurrentControlSet\Services\' + Name, 'ImagePath', ParamStr(0) + ' --name=' + Name, HKEY_LOCAL_MACHINE) 
end; 

procedure TService1.ServiceCreate(Sender: TObject); 
begin 
    Name := Trim(FCommandLineOptions.Values['name']); 
    DisplayName := Name; 
end; 

SaveRegSetting моя собственная процедура и FCommandLineOptions является объектом, который tokenises параметров командной строки.

Смежные вопросы