26/10/2011

Wiele usług w jednym procesie

Home

Istnieje kilka podejść do debugowania usług systemowych. Jeśli chcemy debugować już uruchomioną usługę to możemy skorzystać z opcji Attach to process.... Sprawa jest trudniejsza jeśli chcemy podłączyć się do usługi w momencie jej uruchamiania. W takim wypadku można w kodzie usługi wywołać metodę Debugger.Brake. Są też inne sposoby, na przykład sztuczne opóźnienie startu usługi, tak aby zdążyć się do niej podpiąć.

Ostatnio poznałem nowe, bardzo ciekawe podejście. Polega ono na stworzeniu dodatkowej, pomocniczej "pustej" usługi i zainstalowaniu jej w odpowiedni sposób razem z właściwą usługą. Strukturę przykładowego projektu widać na poniższym rysunku.



Projekt musi również zawierać dwa instalatory (klasa ServiceInstaller), po jednym dla każdej z usług.



W kodzie przekłada się to na coś takiego.
...
this.Installers.AddRange(new System.Configuration.Install.Installer[] {
  this.serviceProcessInstaller1,
  this.serviceInstaller1,
  this.serviceInstaller2});
...
Instalację przeprowadzamy standardowo przy pomocy narzędzia InstallUtil. Zadba ono o to aby zainstalować obie usługi za jednym razem. Następnie, przy debugowaniu najpierw uruchamiamy tą drugą, dodatkową usługę, podczepiamy się do niej przy pomocy opcji Attach to process..., stawiamy pułapkę w kodzie pierwszej usługi i dopiero ją uruchamiamy. To zadziała ponieważ obie usługi zostaną uruchomione w jednym procesie, a co więcej otrzymujemy to za darmo. Odpowiada za to metoda ServiceIntaller.Install, której fragment przytaczam poniżej.
int serviceType = 0x10;
...
if (numberOfServices > 1)
{
  serviceType = 0x20;
}
...
NativeMethods.CreateService(databaseHandle, this.ServiceName, this.DisplayName, 0xf01ff, serviceType, (int) this.StartType, 1, str3, null, IntPtr.Zero, dependencies, servicesStartName, password);
...
CreateService to natywna metoda WinAPI, która dodaje usługę do bazy danych menadżera usług. Istotny jest jej piąty parametr serviceType, może przyjąć kilka wartości ale nas interesują dwie:
  • SERVICE_WIN32_OWN_PROCESS = 0x00000010 oznacza, że każda usługa działa w swoim procesie
  • SERVICE_WIN32_SHARE_PROCESS = 0x00000020 oznacza, że usługi mogą dzielić jeden proces
Jeśli liczba usług jest większa niż 1 to ServiceIntaller.Install używa flagi SERVICE_WIN32_SHARE_PROCESS, a w przeciwnym wypadku SERVICE_WIN32_OWN_PROCESS.

3 comments:

mgrzeg said...

Michał, można skorzystać ze standardowego sposobu, czyli podpinania się do usługi w momencie startu, np. przez odpowiedni klucz w 'Image File Execution Options'

m.g.

Michał Komorowski said...

"...np. przez odpowiedni klucz w 'Image File Execution Options'"

Oczywiście masz rację, a najłatwiej to chyba zrobić przy pomocy programu gflags.exe z Debugging Tools for Windows. To co opisałem, to poprostu kolejna alternatywa, a każdy wybierze to co dla niego najwygodniejsze.

Michał Komorowski

Anonymous said...

Można również zdefiniować stałą (lub skorzystać ze stałej debug) a następnie korzystając z #ifdef uruchomić serwis lub wywołać metodę OnStart

Post a comment