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.

13/09/2011

Okazja do wzięcia udziału w ciekawych kursach

Home

Uniwersytet Stanforda organizuje zdalne kursy poświęcone uczeniu maszyn (ang. machine learning), sztucznej inteligencji oraz bazom danych. Zajęcia są bezpłatne i zaczynają się w październiku, a potrwają do grudnia. Kursy składają się nie tylko z wykładów, ale również z rożnych zadań do rozwiązania, będzie można również zadawać pytania. Moim zdaniem to wspaniała okazja, aby zdobyć albo odświeżyć dużo cennej wiedzy. Na każdy z tych wykładów zapisało się już ponad 50 tysięcy osób!

12/09/2011

IntelliTrace - problem ze zdarzeniem

Home

Jakiś czas temu pracując z IntelliTrace próbowałem zdefiniować zdarzenie diagnostyczne dla pewnej metody. Dla ustalenia uwagi niech jej sygnatura wygląda tak, jak poniżej.

string Flip(string s)

Moim celem było, aby opis zdarzenia zawierał wynik zwrócony przez metodę oraz wartość argumentu s. Inaczej mówiąc, aby w oknie IntelliTrace Events View w Visual Studio 2010 zdarzenie zarejestowane dla wywołania metody z argumentem s="Hello" i wynikiem "olleH" wyglądalo tak:

"olleH" Flip("Hello")

O definiowaniu zdarzeń IntelliTrace już pisałem (Własne zdarzenia IntelliTrace!, Własne zdarzenia IntelliTrace 2) dlatego nie będę opisywał całego procesu. Przytoczę już gotową definicję zdarzenia:
<DiagnosticEventSpecification enabled="true">
  <Bindings>
    <Binding>
      <ModuleSpecificationId>FibTest.exe</ModuleSpecificationId>
        <TypeName>Utilities</TypeName>
        <MethodName>Flip</MethodName>
        <MethodId>Utilities.Flip(System.String):System.String</MethodId>
        <ShortDescription _locID="shortDescription.Utilities.Flip">"{0}" Flip("{1}")</ShortDescription>
        <LongDescription _locID="longDescription.Utilities.Flip">"{0}" Flip("{1}")</LongDescription>
        <DataQueries>
          <DataQuery index="-1" maxSize="100" type="String" query="" />
          <DataQuery index="1" maxSize="100" type="String" query="" />
        </DataQueries>
        <ProgrammableDataQuery>
          <ModuleName></ModuleName>
          <TypeName></TypeName>
        </ProgrammableDataQuery>
    </Binding>
  </Bindings>
  ...
</DiagnosticEventSpecification>
Niestety ku moje zdziwieniu to nie zadziałało. Zdarzenie zostało zarejestrowane, ale w oknie IntelliTrace Events View zamiast zobaczyć upragniony wynik otrzymałem komunikat: An error occured while fetching the data for this event. Zajrzałem, więc do wcześniej zdefiniowanych przez siebie zdarzeń i przypomniałem sobie o jednej rzeczy. Aby odwołać się do wartości zwróconej przez metodę należy ustawić atrybut onReturn.
...
<Binding onReturn="true">
...
Niestety to też nie pomogło. Ponownie zajrzałem więc do wcześniej przygotowanych zdarzeń i na pierwszy rzut oka wszystko wyglądało tak samo. Po chwili zastanowienia doszedłem do wniosku, że przyczyną kłopotów może być to, że próbuję odwołać się zarówno do wartości argumentów jak i do wartości zwracanej przez metodę. Wcześniej czegoś takiego nie próbowałem. Zamiast jednego przygotowałem więc dwa zdarzenia. W jednym odczytuję wartość argumentu przekazanego do metody, a w drugim wynik zwrócony przez metodę.
...
<Binding onReturn="false">
  ...
  <ShortDescription _locID="shortDescription.Utilities.Flip">Flip("{0}")</ShortDescription>
  <LongDescription _locID="longDescription.Utilities.Flip">Flip("{0}")</LongDescription>
  <DataQueries>
    <DataQuery index="1" maxSize="100" type="String" query="" />
  </DataQueries>
  ...
</Binding>
...
...
<Binding onReturn="true">
  ...
  <ShortDescription _locID="shortDescription.Utilities.Flip">Flip returns "{0}"</ShortDescription>
  <LongDescription _locID="longDescription.Utilities.Flip">Flip returns "{0}"</LongDescription>
  <DataQueries>
    <DataQuery index="-1" maxSize="100" type="String" query="" />
  </DataQueries>
  ...
</Binding>
...
To zadziałało, zostały zarejestrowane dwa zdarzenia, jedno z opisem Flip("Hello"), a drugie z opisem Flip returns "olleh". Moim zdaniem to spore ograniczenie IntelliTrace, ale nie ma rady i trzeba o tym po prostu pamiętać.

11/09/2011

Londyn - trochę nietypowa wycieczka

Home

Londyn to miasto odwiedzane rokrocznie przez miliony turystów. Twierdza Tower, Tower Bridge, Pałac Buckingham to tylko z niektórych miejsc, które znajdują się na liście do zobaczenia dla wielu odwiedzających. Ja też nie omieszkałem pokazać się w tych i wielu innych miejscach, ale w tym poście chciałbym zachęcić do wizyty w innym, trochę bardziej nietypowym miejscu. Mam na myśli Thorpe Park czyli wesołe miasteczko zlokalizowane pod Londynem (ok. 40 minut pociągiem + 10 minut autobusem). Bilet kosztuje dla dorosłych 40 funtów, ale cenę można zbić o 35% przy zakupie online lub nawet 50% przy zakupie grupowym (7 biletów).

Miasteczko oferuje bardzo dużo dla miłośników przeciążeń, chyba nawet więcej niż konkurencyjny park Alton Towers. Wspomnę tylko o Stealth, w którym osiągamy prędkość ok. 130 km/h w ciągu 1.8 sekundy, maksymalne przeciążenie to prawie 5G (wciska w fotel), a najwyższy punkt kolejki znajduje się 60m nad ziemią. Robi niesamowite wrażenie, do tego stopnia, że bez zastanowienia zdecydowałem się na drugą przejażdżkę.

Z rzeczy praktycznych to w parku jest tłoczno nawet poza sezonem. Mówię tutaj o weekendach, w ciągu tygodnia może być lepiej. W związku z tym należy przygotować się na długie czekanie, nawet do 2 godzin aby dostać się na kilkunasto sekundową przejażdżkę! Kolejki można ominąć na dwa sposoby. Pierwszy to tzw. single riders. Polega to na tym, że najpierw do wagoników ładowane są osoby z normalnej kolejki i jeśli zostają wolne miejsca (bo ktoś nie chce jechać sam tylko z przyjaciółmi) to wsiada osoba z kolejki dla single riders. Kolejka ta przeważnie jest dużo krótsza niż normalna, ale po pierwsze nie jest dostępna wszędzie, a po drugie dużo zależy od szczęścia. Równie dobrze może być tak, że czas oczekiwania będzie taki jak w normalnej kolejce.

Drugi sposób jest dużo skuteczniejszy, ale nie ma nic za darmo i to dosłownie. Można kupić bilety fast tracks, które pozwalają wejść na atrakcje bez czekania w kolejce. Pojedynczy bilet (jeden przejazd na jednej atrakcji) to koszt od 2 do 5 funtów. Czy warto? Niech każdy odpowie sobie samemu, czy woli czekać czy nie.

Wizytę w Thorper Park szczerze polecam wszystkim, którzy lubią takie atrakcje, szczególnie, że jest zlokalizowany blisko Londynu. Ja bawiłem się tam naprawdę dobrze. Linki do poprzednich postów z serii na temat życia w Londynie: