28/10/2011

Wiele usług w jednym procesie 2

Home

W poście tym wrócę jeszcze do tematu uruchamiania kilku usług w jednym procesie. Otóż, ciekawe jest to, że można konfigurować to zachowanie już po zainstalowaniu usługi. Służy do tego, i nie tylko tego, program wiersza poleceń o nazwie sc. Poniżej przedstawiam przykład jego użycia.

Zacznijmy od pobrania konfiguracji usługi ABC przy pomocy komendy sc query ABC. Przykładowy wynik pokazałem poniżej.
SERVICE_NAME: ABC
TYPE               : 20  WIN32_SHARE_PROCESS
STATE              : 1  STOPPED
  (NOT_STOPPABLE,NOT_PAUSABLE,IGNORES_SHUTDOWN)
WIN32_EXIT_CODE    : 1077       (0x435)
SERVICE_EXIT_CODE  : 0  (0x0)
CHECKPOINT         : 0x0
WAIT_HINT          : 0x0
Jak widać usługa ABC może współdzielić proces z jakąś inną usługą. Efekt działania bardzo ładnie widać w menadżerze zadań. Jeśli uruchomimy usługi: ABC oraz ABCDebug to menadżer zadań pokaże tylko jeden proces.



Aby to zmienić należy użyć komendy sc config ABC type= own. Teraz, po uruchomieniu obu usług, menadżer zadań pokaże dwa procesy.



Do stanu pierwotnego wracamy przy pomocy komendy sc config ABC type= share. Warto zwrócić uwagę na jeszcze jedną rzecz. Spójrzmy na ten scenariusz.
  • Mamy dwie usługi współdzielące proces: ABC oraz ABCDebug..
  • Uruchamiamy obie i menadżer zadań pokazuje jeden nowy proces: WindowsService1.exe.
  • Zatrzymujemy usługę ABC.
  • Usługa ABCDebug nadal działa.
  • sc config ABC type= own
  • Uruchamiamy usługę ABC i teraz menadżer zadań pokazuje dwa procesy WindowsService1.exe.
  • Zatrzymujemy usługę ABC
  • sc config ABC type= share
  • Ponownie uruchamiamy usługę ABC i menadżer zadań znowu pokazuje jeden proces WindowsService1.exe.
Czyli w czasie kiedy zmienialiśmy konfigurację usługi ABC usługa ABCDebug cały czas działała i w niczym to nie przeszkadzało.

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.

24/10/2011

PrintScreen

Home

Ostatnimi czasy zdarzyło się, że musiałem intensywnie korzystać z przycisku Print Scrn, tworzyć wiele zrzutów ekranu, a potem jeszcze edytować je w programie graficznym. W pewnym momencie stwierdziłem, że proces ten trzeba jakoś zautomatyzować. Z pomocą przyszedł program PrintScreen.

W wersji podstawowej jest bezpłatny. Reaguje na standardowy przycisk Print Scrn ale można to zmienić. Zrzuty ekranu wypluwa w wybranym formacie, do wskazanego katalogu. Nazwy plików mogą być generowane automatycznie np.: ScreenSchot001, ScreenSchot002 itd. Bardzo spodobało mi się to, że jeśli usuniemy np.: plik ScreenSchoot002 i w ten sposób powstanie luka w numeracji to zostanie ona zapełniona przez następny plik. Program umie również wyświetlić podgląd zrzutu, a przed zapisaniem na dysk umożliwia np.: zmianę wielkości obrazka. W zależności od konfiguracji robi zrzut całego ekranu, wybranego okna lub wskazanego fragmentu.

Nie jest to nic co przyprawia o zawrót głowy ale doskonale spełnia swoją funkcję - po prostu kawał dobrze wykonanej roboty. Program ten zagości na stale w mojej skrzynce narzędziowej i polecam go każdemu komu nie wystarcza standardowa funkcjonalność systemu operacyjnego dotycząca tworzenia zrzutów ekranu.