Skillnaden mellan en tjänst och en applikation. Vilka Windows-tjänster som behövs och vilka som kan inaktiveras. Framväxten av triggerbaserade tjänster

Ur mjukvarukompatibilitetssynpunkt. Så det är bara naturligt att vi återkommer till att diskutera tjänster i Windows 7-sammanhang. Men den här gången ska vi prata om några av fördelarna med att optimera de tjänster som finns tillgängliga i Windows 7. Den här artikeln handlar om en ny funktion i Windows 7 - Trigger Start Services. Men innan vi tittar på API:t, låt oss ta en titt på den stora bilden av tjänsterna.

Vad är tjänster?

En tjänst är en intern mekanism inbyggd i Windows operativsystem. Du kan tänka dig tjänster som speciella applikationer som körs oavsett det aktuella användarkontexten. Tjänster skiljer sig från vanliga applikationer genom att de kan konfigureras för att fungera från det ögonblick som systemet slås på (startas) tills det stängs av, utan att användaren kräver närvaro. Det vill säga tjänster kan köras även om användaren inte är inloggad.

Vi föredrar att tänka på tjänster som att köra uppgifter som körs i bakgrunden och som inte påverkar användarens verksamhet. Tjänster i Windows ansvarar för alla typer av bakgrundsaktivitet, från Remote Procedure Call (RPC), Printer Spooler och hela vägen till Network Location Awareness.

Under åren har Windows växt och antalet tjänster likaså. Låt oss vara ärliga, bakgrundstjänster i Windows är lite jobbiga - operativsystemet kommer med många tjänster ur lådan. Dessutom lägger oberoende mjukvaruutvecklare (ISV) och deras applikationer till ännu fler tjänster. Till exempel mjukvaruuppdateringstjänster. Vissa tjänster är dock kritiska och krävs under uppstartsprocessen, medan andra behövs senare när en specifik användare loggar in, och andra behöver inte starta alls förrän de anropas. Trots detta, när du tittar på listan över tjänster som körs för närvarande, ser du många objekt som inte behöver fungera 24x7.

Vad är det för fel på tjänster som fungerar 24 timmar om dygnet, 7 dagar i veckan?

Det finns flera problem förknippade med 24x7-tjänster. För det första, varför ska något köras (även i bakgrunden) om det inte behövs? Alla pågående processer (inklusive tjänster) använder värdefullt minne och CPU-resurser som kan användas för andra applikationer och tjänster. Om du räknar alla tjänster som körs vid ett givet ögonblick, summerar de till en betydande mängd minne, handtag, trådar och CPU-användning. Alla dessa "bortkastade" resurser minskar datorns totala prestanda, minskar dess lyhördhet och får datorn att framstå som trög och långsam. Dessutom, eftersom många tjänster är konfigurerade att starta automatiskt (börjar fungera när systemet startar), påverkar de datorns starttid.

För det andra har dessa bortkastade resurser en direkt inverkan på energiförbrukningen. Ju större belastningen på processorn är, desto mer ström förbrukar datorn. Detta kan vara kritiskt på bärbara datorer och kan minska batteritiden med flera timmar.

För det tredje, att köra improduktiv programvara kontinuerligt kan leda till minnesläckor och generell systeminstabilitet. Detta leder till fel på applikationer och i slutändan datorn.

Slutligen, om tjänsten fungerar 24x7, och om det är en välkänd tjänst (som alla populära applikationer kan ha, såsom PDF Reader), skapar detta en stor attackyta. En angripare kan använda information om att en viss populär applikation installerar en 24x7-tjänst och försöka hacka den för att få tillgång till datorn.

Med allt detta sagt kanske du undrar varför så många utvecklare konfigurerar sina tjänster så att de körs hela tiden om de har ett annat alternativ. Redan före Windows 7 fanns det flera alternativ tillgängliga för att starta tjänster:

  • Inaktiverad inaktiverar en tjänst helt och hindrar den och beroende tjänster från att starta - vilket betyder att användaren måste aktivera tjänsten manuellt från Kontrollpanelen eller Kommandotolken
  • Manuell startar en tjänst efter behov (på grund av beroenden av andra tjänster) eller när tjänsten anropas från applikationen med hjälp av lämpliga API:er, som kommer att visas nedan
  • Automatisk startar en tjänst vid inloggning
  • Automatisk fördröjd– en nyare typ av start som introduceras i Windows Vista, med vilken tjänsten startar efter att uppstarten har slutförts och de initiala operationerna har slutförts, vilket påskyndar systemstarten.

Tyvärr fortsätter många ISV:er (inklusive Microsoft själv) att ställa in sina tjänster på Automated eller Automatic Delayed eftersom det verkar vara den enklaste lösningen för alla. Tjänsten körs helt enkelt 24x7 och är alltid tillgänglig, vilket eliminerar behovet av att kontrollera beroenden eller om tjänsten körs.

Det finns många exempel på befintliga tjänster som kan använda mycket mindre resurser och bli säkrare utan att arbeta 24x7. Tänk till exempel på en uppdateringstjänst som letar efter nya uppdateringar av en applikation. Om datorn inte är ansluten till nätverket och inte har en IP-adress, varför ska det fungera? Det kan inte göra någonting, så varför lämna ett program igång som inte gör någonting? Tänk på policyhanteringstjänsten, som används när du ändrar grupppolicyer eller när en dator går med i eller lämnar en domän, men nu när datorn är ansluten till mitt hemnätverk körs tjänsten återigen på tom.

Framväxten av triggerbaserade tjänster

Lösningen på ovanstående problem är att flytta tjänsten från "alltid på-tillståndet" till andra typer av bakgrundsaktivitet, såsom schemalagda uppgifter eller utlösta tjänster. Den här artikeln handlar om Windows 7 Trigger Start Services. Många intressanta saker kan sägas om Windows 7 Scheduled Tasks, som kommer att göras i efterföljande artiklar.

Senast uppdaterad: 2015-10-31

En av de viktigaste komponenterna i Windows OS är tjänster. Det är faktiskt separata applikationer som inte har något grafiskt gränssnitt och som utför olika uppgifter i bakgrunden. Tjänster kan startas när operativsystemet startar, eller när som helst när användaren arbetar. Ett vanligt exempel på tjänster är olika webbservrar som i bakgrunden lyssnar på en specifik port för anslutningar, och om det finns anslutningar interagerar de med dem. Det kan också vara olika hjälpuppdateringstjänster för andra installerade program som kontaktar servern för att ta reda på om det finns en ny version av applikationen. I allmänhet kan vi öppna tjänstepanelen och se själva alla installerade och pågående tjänster:

Låt oss titta på hur du skapar dina egna tjänster i C#. Som uppgift som ska implementeras kommer vi att välja att övervaka ändringar i en specifik mapp i filsystemet. Låt oss nu skapa en tjänst för att köra den.

Låt oss först skapa ett nytt projekt, som kommer att vara av typen Windows Service. Låt oss kalla projektet FileWatcherService:

Visual Studio genererar sedan ett projekt som har allt du behöver. Även om vi inte nödvändigtvis behöver välja den här typen av projekt, kan vi skapa ett klassbiblioteksprojekt och sedan definiera alla nödvändiga klasser i det.

Så det nya projektet ser ut så här:

Det finns också en fil Program.cs och det finns själva tjänstenoden Service1.cs.

Tjänsten representerar en normal applikation, men den startar inte av sig själv. Alla samtal och åtkomst till det går via servicekontrollhanteraren (Service Control Manager eller SCM). När en tjänst startar automatiskt vid systemstart eller manuellt anropar SCM Main-metoden i klassen Program:

Statisk klass Program ( static void Main() ( ServiceBase ServicesToRun; ServicesToRun = new ServiceBase ( new Service1() ); ServiceBase.Run(ServicesToRun); ) )

Main-metoden är definierad som standard för att köra flera tjänster samtidigt, som är definierade i ServicesToRun-matrisen. Men som standard innehåller projektet bara en tjänst, Service1. Själva lanseringen utförs med hjälp av Run-metoden: ServiceBase.Run(ServicesToRun) .

Tjänsten som startas representeras av Service1.cs-noden. Detta är dock inte en enkel kodfil. Om vi ​​öppnar den här noden kommer vi att se tjänstdesignerfilen Service1.Designer.cs och klassen Service1.

Klassen Service1 representerar faktiskt tjänsten. Som standard har den följande kod:

Använda System; använder System.Collections.Generic; använder System.ComponentModel; använder System.Data; använder System.Diagnostics; använder System.Linq; använder System.ServiceProcess; använder System.Text; använda System.Threading.Tasks; namnområde FileWatcherService ( offentlig delklass Service1: ServiceBase ( public Service1() ( InitializeComponent(); ) protected override void OnStart(string args) ( ) protected override void OnStop() ( ) ) )

Serviceklassen måste ärva från ServiceBase-basklassen. Den här klassen definierar ett antal metoder, av vilka de viktigaste är metoden OnStart() som startar de åtgärder som utförs av tjänsten och metoden OnStop() som stoppar tjänsten.

Efter att SCM anropat Main-metoden och registrerat tjänsten anropas den direkt genom att köra OnStart-metoden.

När vi skickar ett kommando för att stoppa en tjänst i tjänstkonsolen eller via kommandoraden, anropar SCM OnStop-metoden för att stoppa den.

Utöver dessa två metoder i serviceklassen kan du åsidosätta flera fler metoder i ServiceBase-basklassen:

    OnPause: Anropas när tjänsten är pausad

    OnContinue: Anropas när en tjänst återupptas efter att den har stängts av

    OnShutdown: Anropas när Windows stängs av

    OnPowerEvent: Anropas när strömläget ändras

    OnCustomCommand: Anropas när en tjänst tar emot ett anpassat kommando från Service Control Manager (SCM)

I konstruktorn för klassen Service1 anropas metoden InitializeComponent() som definieras i designerfilen Service1.Designer.cs:

Namespace FileWatcherService ( partiell klass Service1 ( privat System.ComponentModel.IContainer komponenter = null; skyddad åsidosättande void Dispose(bool disposing) ( if (disponing && (components != null)) ( komponenter.Dispose(); ) base.Dispose(disposing) ); ) private void InitializeComponent() ( komponenter = new System.ComponentModel.Container(); this.ServiceName = "Service1"; ) ) )

Det enda som behöver noteras i det är att ställa in tjänstens namn (ServiceName-egenskapen):

This.ServiceName = "Service1";

Detta är namnet som kommer att visas i tjänstekonsolen efter installation av den här tjänsten. Vi kan ändra det, eller så kan vi lämna det som det är.

Låt oss nu ändra servicekoden enligt följande:

Använda System; använder System.ServiceProcess; använder System.IO; använder System.Threading; namnområde FileWatcherService ( offentlig partiell klass Service1: ServiceBase ( Logger logger; public Service1() ( InitializeComponent(); this.CanStop = true; this.CanPauseAndContinue = true; this.AutoLog = true; ) skyddad åsidosättning void OnStart(string args) ( logger = new Logger(); Thread loggerThread = new ThreadStart(logger.Start)); class Logger ( FileSystemWatcher watcher; object obj = new object(); bool enabled = true; public Logger() ( watcher = new FileSystemWatcher("D:\\Temp"); watcher.Deleted += Watcher_Deleted; watcher.Created + = Watcher_Created; watcher.Changed += Watcher.Renamed += Watcher_Renamed ) public void Start() ( watcher.EnableRaisingEvents = true; while(enabled) ( Thread.Sleep(1000); ) ) public void Stop() ( watcher.EnableRaisingEvents = false; enabled = false; // byter namn på filer privat void Watcher_Renamed(objektavsändare, RenamedEventArgs e) ( string fileEvent = "döpt om till " + e.FullPath; string filePath = e.OldFullPath; RecordEntry(fileEvent, filePath); ) // ändra filer privat void Watcher_Changed(objektavsändare, FileSystemEventArgs e) ( string fileEvent = "changed"; string filePath = e.FullPath; RecordEntry(fileEvent, filePath); ) // skapa filer privat void Watcher_Created(objektavsändare, FileSystemEventArgs e) ( string fileEvent = "created"; string filePath = e.FullPath; RecordEntry(fileEvent, filePath); ) // radering av filer privat void Watcher_Deleted(objektavsändare, FileSystemEventArgs e) ( string fileEvent = "raderad"; string filePath = e.FullPath; .WriteLine(String.Format("(0) file (1) was (2)", DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss"), filePath, fileEvent)); ; ) ) )

Nyckelklassen som kapslar in all funktionalitet är Logger-klassen. Med hjälp av FileSystemWatcher-objektet kommer det att övervaka ändringar i mappen D://Temp. Metoden Start() anger att vi kommer att se efter ändringar genom FileSystemWatcher-objektet. Och allt arbete kommer att fortsätta så länge som den aktiverade booleska variabeln är sann. Och metoden Stop() kommer att tillåta klassen att avslutas.

FileSystemWatcher-händelser låter dig övervaka alla ändringar i en bevakad mapp. Detta kommer att registrera ändringar i filen templog.txt. För att undvika resursracing för filen templog.txt, i vilken ändringar registreras, blockeras inspelningsproceduren av lock(obj)-stubben.

Som ett resultat, efter att ha skapat, ändrat, döpt om och tagit bort, kommer loggfilen att innehålla något som:

07/30/2015 12:15:40 fil D:\Temp\New text document.txt skapades 07/30/2015 12:15:46 fil D:\Temp\New text document.txt bytte namn till D:\ Temp\hej txt 07/30/2015 12:15:55 fil D:\Temp\hello.txt modifierades 07/30/2015 12:15:55 fil D:\Temp\hello.txt modifierades 07/30 /2015 12:16:01 fil D: \Temp\hello.txt har raderats

I själva tjänsteklassen Service1 ställs ett antal alternativ in i konstruktorn:

This.CanStop = sant; // tjänsten kan stoppas detta.CanPauseAndContinue = true; // tjänsten kan pausas och sedan fortsätta detta.AutoLog = true; // tjänsten kan skriva till loggen

I metoden OnStart() anropas en ny tråd för att starta Logger-objektet:

Skyddad åsidosättning void OnStart(string args) (logger = new Logger(); Thread loggerThread = new Thread(new ThreadStart(logger.Start)); loggerThread.Start(); )

Den nya tråden behövs eftersom den aktuella tråden endast bearbetar SCM-kommandon och måste återvända från OnStart-metoden så snabbt som möjligt.

När ett kommando tas emot från SCM för att stoppa tjänsten utlöses OnStop-metoden, som anropar logger.Stop()-metoden. Den ytterligare fördröjningen gör att loggertråden stoppas:

Skyddad åsidosättande void OnStop() ( logger.Stop(); Thread.Sleep(1000); )

Serviceklassen i sig räcker dock inte till. Vi behöver också skapa en serviceinstallatör.

Eller skrivbordet för användare (både lokalt och fjärranslutet), men för vissa tjänster är ett undantag möjligt - interaktion med konsolen (session nummer 0, där användaren är registrerad lokalt eller när tjänsten startas mstsc med /console-växeln).

Det finns flera lägen för tjänster:

  • förbjuden att starta;
  • manuell start (på begäran);
  • automatisk start när datorn startar;
  • automatisk (fördröjd) start (introducerad i Windows Vista och Windows Server 2008);
  • obligatorisk service/förare (automatisk start och oförmåga (för användaren) att stoppa tjänsten).

Bakgrundsläge

Starta, stoppa och ändra Windows-tjänster

Tjänster och deras attribut kan ändras i MMC:n:

Olika versioner av operativsystem kan ha vissa tjänster och inte andra. Vissa applikationer och program som installeras separat kan också skapa sina egna tjänster.

Lista över Microsoft Windows-operativsystemtjänster

Visningsnamn Service namn Funktioner Beskrivning
DHCP-klient DHCP Registrerar och uppdaterar IP-adresser och DNS-poster för den här datorn. Om den här tjänsten stoppas kommer den här datorn inte att kunna erhålla dynamiska IP-adresser och utföra DNS-uppdateringar.
DNS-klient Dnscache DNS-klienttjänsten (dnscache) cachelagrar DNS-namn (Domain Name System) och registrerar det fullständiga namnet på en given dator. Om tjänsten stoppas kommer DNS-namnupplösningen att fortsätta. Resultaten av DNS-namnköer kommer dock inte att cachelagras och datornamnet kommer inte att registreras.
KtmRm för distribuerad transaktionskoordinator KtmRm Koordinerar transaktioner mellan MSDTC och Kernel Transaction Manager (KTM).
Redo uppsving EMDMgmt Redo uppsving Stöd för att förbättra systemets prestanda med hjälp av ReadyBoost-teknik.
Superhämtning SysMain Superhämtning Underhåller och förbättrar systemets prestanda.
Windows Audio Audiosrv Hantera ljudverktyg för Windows-program. Om den här tjänsten stoppas kommer ljudenheter och effekter inte att fungera korrekt.
Windows CardSpace idsvc Ger en säker förmåga att skapa, hantera och exponera digitala identiteter.
Automatisk uppdatering WUAUSERV Inkluderar nedladdning och installation av Windows-uppdateringar. Om tjänsten är inaktiverad kommer den här datorn inte att kunna använda Automatiska uppdateringar eller Windows Update-webbplatsen.
Remote Procedure Call (RPC) RpcSs Tillhandahåller mappning mellan ändpunkter och andra RPC-tjänster.

Lista över tjänster skapade av Microsofts applikationer och program

Exempel på tjänster skapade av tredjepartsapplikationer och program

Visningsnamn Service namn Funktioner Beskrivning
ESET HTTP-server EhttpSrv antivirusskydd ESET HTTP Server-komponent

Hur man kör en applikation som en Windows-tjänst

Är det möjligt att köra en klientapplikation som en tjänst? I en av dem beskrev jag sätt att skapa en Windows-tjänst med vanliga OS-verktyg. Men inte alla konsolapplikationer kan köras som en tjänst, och program med ett grafiskt gränssnitt kan i princip inte fungera på detta sätt. Men det är fortfarande möjligt att köra applikationen som en tjänst, och ett program med ett originalnamn hjälper oss med detta Icke-sugande tjänstechef.

NSSM är gratis programvara med öppen källkod och stöder alla Microsofts operativsystem från Windows 2000 till Windows 8. NSSM kräver ingen installation, bara ladda ner och packa upp den. Distributionen inkluderar versioner för 32- och 64-bitars operativsystem. Du kan hämta programmet från webbplatsen nssm.cc, för tillfället är den senaste stabila versionen 2.21.1, som jag kommer att använda.

För att demonstrera funktionerna hos NSSM, låt oss prova att köra Windows Notepad som en tjänst på Windows 8.1.

Skapa en tjänst

För att skapa en tjänst som heter anteckningsblock starta kommandokonsolen, gå till mappen med den uppackade NSSM (för 64-bitars Windows) och ange kommandot nssm install notepad, vilket öppnar NSSMs grafiska installationsfönster. För att skapa en tjänst, ange bara sökvägen till den körbara filen i sökvägsfältet och klicka på knappen "Installera tjänst". Dessutom kan du i fältet Alternativ ange vilka nycklar som krävs för att starta tjänsten.

Du kan också ange några ytterligare parametrar när du skapar en ny tjänst.

Fliken Shutdown listar avstängningsmetoderna och tidsgränserna som används när programmet stängs av normalt eller kraschar. När NSSM tar emot ett stoppkommando (till exempel när en applikation stängs av) försöker den stoppa den kontrollerade applikationen på ett normalt sätt. Om applikationen inte svarar kan NSSM tvångsmässigt avsluta alla processer och delprocesser i denna applikation.

Det finns fyra steg för att stänga av programmet, och som standard kommer de att användas i denna ordning:

I det första skedet försöker NSSM generera och skicka en händelse Ctrl+C. Denna metod fungerar bra för konsolapplikationer eller skript, men är inte tillämplig för grafiska applikationer;
NSSM upptäcker sedan alla fönster som skapats av applikationen och skickar dem ett WM_CLOSE-meddelande, vilket gör att applikationen avslutas;
Det tredje steget är att NSSM beräknar alla trådar som skapats av applikationen och skickar dem ett WM_QUIT-meddelande, som tas emot om applikationen har en trådmeddelandekö;
Som en sista utväg kan NSSM anropa TerminateProcess()-metoden, vilket tvingar applikationen att avslutas.

Det är möjligt att inaktivera vissa eller till och med alla metoder, men olika metoder fungerar för olika applikationer och det rekommenderas att lämna allt som det är för att säkerställa att applikationen stängs av korrekt.

Som standard, när en tjänst kraschar, försöker NSSM starta om den. På fliken "Avsluta åtgärder" kan du ändra den automatiska åtgärden när programmet avslutas onormalt, samt ställa in en fördröjning innan programmet startar om automatiskt.

På fliken "Input/Output (I/O)" kan du ställa in omdirigeringen av applikationsinmatning/-utgång till en specificerad fil.

På fliken "Miljö" kan du ställa in nya miljövariabler för tjänsten eller åsidosätta befintliga.

Du kan inte heller använda det grafiska skalet och omedelbart skapa en tjänst i konsolen med följande kommando:

nssm installera anteckningsblock ″C:\Windows\system32\notepad.exe″

Service management

Efter att ha skapat tjänsten med NSSM, gå till snapin-modulen Tjänster och hitta anteckningsblockstjänsten. Som du kan se, är det inte annorlunda än andra tjänster, vi kan också starta det, stoppa det eller ändra startläget. Observera dock att nssm.exe är listad som den körbara filen.

Och om vi går till Aktivitetshanteraren kommer vi att se följande bild: NSSM körs som huvudprocessen (förälder), anteckningstjänsten körs som sin underordnade process, och applikationen Anteckningar körs redan i denna underordnade process.

Ta bort en tjänst

För att ta bort en tjänst anger du kommandot nssm remove notepad och bekräftar borttagningen. Och genom att ange kommandot nssm remove notepad confirm , kan du göra utan bekräftelse.

Starta en tjänst interaktivt

Den största skillnaden mellan en användarapplikation och en tjänst är att applikationen, när den väl har startat, kan kräva ytterligare användaråtgärder för att fortsätta köra, som att trycka på en knapp eller ange ett kommando. För att göra detta måste du få tillgång till det, vilket, som det visar sig, inte är så lätt att göra.

För att starta en tjänst i interaktivt läge måste du öppna dess egenskaper i snapin-modulen Tjänster och på fliken "Logga in", kryssa i kryssrutan "Tillåt interaktion med skrivbordet".

Och då börjar mirakel :) En tjänst som lanseras i interaktivt läge öppnas i en isolerad session (session 0). Denna session kan endast nås genom att använda Interactive Services Detection Service (ui0detect), som övervakar uppstarten av interaktiva tjänster på datorn och utfärdar en varning. I Windows 7\Server 2008 är den här tjänsten aktiv som standard, men i Windows 8\Server 2012 är den inaktiverad och visas inte i Services grafiska snap-in (åtminstone jag hittade den inte där). Dessutom, om du hittar denna mystiska tjänst och försöker starta den, kommer du att få ett felmeddelande.

Men faktum är att för att köra det måste du tillåta interaktiva tjänster att köra på din dator. Öppna därför registerredigeraren, hitta en DWORD-typparameter med namnet i avsnittet HKLM\System\CurrentControlSet\Control\Windows Inga interaktiva tjänster och ställ in dess värde till 0 .

Öppna sedan PowerShell-konsolen och starta upptäcktstjänsten med kommandot:

Start-Service -Name ui0detect

Efter att ha sett till att detekteringstjänsten körs startar vi om anteckningstjänsten och vi får det här fönstret. Välj "Visa meddelande"

och vi befinner oss i nollsessionen där vår applikation körs. Sedan utför vi nödvändiga åtgärder med den och återvänder tillbaka.

Detta är en intressant lösning för att köra applikationer som Windows-tjänster. Inte den vackraste, men ganska överens med namnet :)


Windows NT-tjänsten är en speciell process som har ett enhetligt gränssnitt för interaktion med Windows NT-operativsystemet. Tjänsterna är uppdelade i två typer - Win32-tjänster, som interagerar med operativsystemet via Service Control Manager (SCM), och drivrutiner, som använder drivrutinsprotokollet för Windows NT. Vi kommer bara att diskutera Win32-tjänster senare i den här artikeln.

Tillämpning av tjänster

En av tjänstens viktigaste egenskaper är icke-interaktivitet. En typisk tjänst körs i bakgrunden obemärkt av den genomsnittliga användaren. På grund av detta är tjänsterna mest lämpade för att implementera följande typer av applikationer:

  • Servrar i klient-serverarkitektur (till exempel MS SQL, MS Exchange Server)
  • Nätverkstjänster Windows NT (server, arbetsstation);
  • Serverkomponenter (i termer av funktionalitet) i distribuerade applikationer (till exempel alla typer av övervakningsprogram).

Grundläggande egenskaper hos tjänster

Tjänsten särskiljs från en vanlig Win32-applikation genom tre huvudegenskaper. Låt oss titta på var och en av dem.

För det första är det möjligt att korrekt stoppa (avbryta) tjänsten. En användare eller annan applikation som använder standardmekanismer har förmågan att ändra tillståndet för en tjänst - flytta den från ett körläge till ett pausat läge, eller till och med stoppa den från att köras. I det här fallet, innan den ändrar sitt tillstånd, får tjänsten ett speciellt meddelande, tack vare vilket den kan utföra de åtgärder som är nödvändiga för att övergå till ett nytt tillstånd, till exempel frigöra ockuperade resurser.

För det andra möjligheten att starta tjänsten innan användaren registreras och, som ett resultat, möjligheten att arbeta utan en registrerad användare överhuvudtaget. Alla tjänster kan startas automatiskt när operativsystemet startar och börja fungera även innan användaren loggar in i systemet.

Och slutligen, förmågan att arbeta i ett godtyckligt säkerhetssammanhang. Windows NT-säkerhetskontexten definierar en uppsättning åtkomsträttigheter för en process till olika systemobjekt och data. Till skillnad från en typisk Win32-applikation, som alltid körs i säkerhetskontexten för den användare som för närvarande är inloggad på systemet, kan säkerhetskontexten för dess exekvering för en tjänst bestämmas i förväg. Detta innebär att en tjänst kan ha sin uppsättning åtkomsträttigheter till systemobjekt definierade i förväg och därmed begränsa omfattningen av dess verksamhet. För tjänster finns det en speciell typ av standardsäkerhetskontext som kallas Lokalt system. En tjänst som körs i detta sammanhang har endast rättigheter till resurser på den lokala datorn. Inga nätverksoperationer kan utföras med lokala systemrättigheter, eftersom detta sammanhang bara är vettigt på den lokala datorn och inte känns igen av andra datorer i nätverket.

Interaktion av tjänsten med andra applikationer

Alla program som har lämpliga rättigheter kan interagera med tjänsten. Interaktion innebär först och främst att ändra tjänstens tillstånd, det vill säga att överföra den till ett av tre tillstånd - kör (Start), avstängd (Paus), stoppar och utförs genom att skicka in SCM-förfrågningar. Förfrågningar är av tre typer - meddelanden från tjänster (fixar deras tillstånd), förfrågningar relaterade till att ändra konfigurationen av en tjänst eller erhålla information om den, och applikationsbegäranden om att ändra tillståndet för en tjänst.

För att hantera en tjänst måste du först få dess handtag med hjälp av OpenService Win32 API-funktionen. StartService-funktionen startar en tjänst. Vid behov ändras tjänstens tillstånd genom att anropa ControlService-funktionen.

Tjänstedatabas

Information om varje tjänst lagras i registret - i nyckeln HKLM\SYSTEM\CurrentControlSet\Services\ServiceName. Den innehåller följande information:

  • Servicetyp. Anger om denna applikation implementerar endast en tjänst (exklusiv) eller om det finns flera av dem i applikationen. En exklusiv tjänst kan fungera i alla säkerhetssammanhang. Flera tjänster inom samma applikation kan endast köras i LocalSystem-sammanhang.
  • Starttyp. Automatisk - tjänsten startar vid systemstart. På begäran - tjänsten startas manuellt av användaren. Avaktiverad - Tjänsten kan inte startas.
  • Namnet på den körbara modulen (EXE-fil).
  • Startorder i förhållande till andra tjänster. I vissa fall, för att en tjänst ska fungera korrekt, måste en eller flera andra tjänster vara igång. I det här fallet innehåller registret information om de tjänster som startade före denna.
  • Säkerhetskontexten för körning av tjänsten (nätverksnamn och lösenord). Som standard är säkerhetskontexten LocalSystem.

Applikationer som behöver hämta information om en tjänst eller ändra en tjänstinställning måste i huvudsak ändra informationen i tjänstens databas i registret. Detta kan göras med hjälp av motsvarande Win32 API-funktioner:

  • OpenSCManager, CreateService, OpenService, CloseServiceHandle - för att skapa (öppna) en tjänst;
  • QueryServiceConfig, QueryServiceObjectSecurity, EnumDependentServices, EnumServicesStatus - för att få information om tjänsten;
  • ChangeServiceConfig, SetServiceObjectSecurity, LockServiceDatabase, UnlockServiceDatabase, QueryServiceLockStatus - för att ändra tjänstens konfigurationsinformation.

Tjänstens interna struktur.

För att detta ska ske måste applikationen struktureras därefter, nämligen inkludera en viss uppsättning funktioner (i C++-termer) med en viss funktionalitet. Låt oss titta kort på var och en av dem.

huvudfunktion

Som du vet är huvudfunktionen startpunkten för alla Win32-konsolapplikationer. När tjänsten startar börjar koden för denna funktion att exekveras först. Inom 30 sekunder från start måste huvudfunktionen anropa StartServiceCtrlDispatcher för att upprätta en anslutning mellan applikationen och SCM. All kommunikation mellan någon tjänst i en given applikation och SCM utförs inom StartServiceCtrlDispatcher-funktionen, som avslutas först efter att alla tjänster i applikationen har stoppats.

ServiceHuvudfunktion

Utöver den processövergripande ingångspunkten finns det även en separat ingångspunkt för var och en av de tjänster som implementeras i applikationen. Namnen på funktionerna som är serviceingångar (för enkelhets skull, låt oss kalla dem alla likadana - ServiceMain) skickas till SCM i en av parametrarna när StartServiceCtrlDispatcher anropas. När varje tjänst startar skapas en separat tråd för att köra ServiceMain.

Efter att ha fått kontroll måste ServiceMain först registrera en hanterare av tjänsteförfrågningar, Handler-funktionen, för varje tjänst i applikationen. Detta följs vanligtvis i ServiceMain av några åtgärder för att initiera tjänsten - allokering av minne, läsning av data, etc. Dessa åtgärder måste åtföljas av SCM-meddelanden om att tjänsten fortfarande håller på att starta och att inga fel har inträffat. Aviseringar skickas med anrop till funktionen SetServiceStatus. Alla anrop utom det allra sista måste vara med parametern SERVICE_START_PENDING, och det senaste måste ha parametern SERVICE_RUNNING. Frekvensen för samtalen bestäms av tjänsteutvecklaren baserat på följande villkor: varaktigheten av tidsintervallet mellan två angränsande SetServiceStatus-anrop får inte överstiga värdet på parametern dwWaitHint som skickas till SCM under det första av de två samtalen. Annars kommer SCM, som inte får nästa avisering i tid, att tvångsstoppa tjänsten. Denna metod låter dig undvika situationen för tjänsten i början som ett resultat av förekomsten av vissa fel (kom ihåg att tjänster vanligtvis är icke-interaktiva och kan startas i frånvaro av användaren). Vanlig praxis är att SCM meddelas efter slutförandet av nästa initieringssteg.

Handlarfunktion

Som nämnts ovan är Handler en prototyp av en callback-funktion, en service request-hanterare, unik för varje tjänst i applikationen. Hanteraren anropas när tjänsten tar emot en begäran (start, paus, återuppta, stopp, meddelande om aktuellt tillstånd) och utför de nödvändiga åtgärderna i enlighet med begäran, varefter den rapporterar det nya tillståndet till SCM.

En begäran bör särskilt noteras - begäran som mottogs när systemet stängdes av (Shutdown). Denna begäran signalerar behovet av att avinitiera och avsluta. Microsoft säger att varje tjänst får 20 sekunder på sig att stängas av innan den tvingas stoppa. Tester har dock visat att detta villkor inte alltid är uppfyllt och tjänsten tvingas upphöra innan denna tidsperiod har gått ut.

Servicesäkerhetssystem

Alla åtgärder på tjänster kräver att applikationen har lämpliga rättigheter. Alla applikationer har rättigheter att ansluta till SCM, räkna upp tjänster och kontrollera om tjänstedatabasen är blockerad. Endast applikationer med administrativa rättigheter kan registrera en ny tjänst i systemet eller blockera tjänstedatabasen.

Varje tjänst har en säkerhetsbeskrivning som beskriver vilka användare som har rättigheter till vilken operation. Standard:

  • Alla användare har rättigheterna SERVICE_QUERY_CONFIG, SERVICE_QUERY_STATUS, SERVICE_ENUMERATE_DEPENDENTS, SERVICE_INTERROGATE och SERVICE_USER_DEFINED_CONTROL;
  • Användare som tillhör gruppen Power Users och LocalSystem-kontot har dessutom rättigheterna SERVICE_START, SERVICE_PAUSE_CONTINUE och SERVICE_STOP;
  • Användare som tillhör grupperna Administratörer och Systemoperatörer har rättigheten SERVICE_ALL_ACCESS.

Tjänster och interaktivitet

Som standard kan interaktiva tjänster endast köras i säkerhetskontexten LocalSystem. Detta beror på särdragen med att visas på skärmen i Windows NT, där det till exempel finns ett objekt som "Desktop", att arbeta med vilket du behöver ha lämpliga åtkomsträttigheter, som ett godtyckligt konto annat än LocalSystem kanske inte har. Trots att denna begränsning i de allra flesta fall inte är betydande, finns det ibland ett behov av att skapa en tjänst som skulle visa information på skärmen och samtidigt exekveras i ett annat säkerhetssammanhang än LocalSystem, för till exempel en applikationsserverkomponent för att köra applikationer på en fjärrdator.

Kodavsnitt från . illustrerar denna möjlighet.

I detta fragment, som svar på en begäran som skickats av klientsidan av applikationen som en RPC-konsekvens, visar tjänsten ett textmeddelande på monitorskärmen.

Exempeltjänst (nyckelkodavsnitt)

Låt oss titta på exemplet med nyckelfragment av en applikation i C++ som implementerar en Windows NT-tjänst. För tydlighetens skull har icke väsentliga delar av koden utelämnats.

huvudfunktion

Huvudfunktionskoden visas i B.

ServiceHuvudfunktion

En egenskap hos koden som finns i ServiceMain är att det ofta är omöjligt att i förväg förutsäga exekveringstiden för en viss operation, särskilt med tanke på att dess exekvering sker på ett operativsystem med förebyggande multitasking. Om operationen tar längre tid än det tidsintervall som anges i SetServiceStatus-anropsparametern, kommer tjänsten inte att kunna skicka nästa meddelande i tid, vilket gör att SCM stoppar sin drift. Exempel på potentiella operationer är anrop till nätverksfunktioner med stora timeouts eller samtidig läsning av en stor mängd information från ett långsamt medium. Dessutom är detta tillvägagångssätt helt otillämpligt vid felsökning av en tjänst, eftersom exekvering av programmet i debuggern åtföljs av långa pauser, som är nödvändiga för utvecklaren.

För att övervinna detta problem bör alla operationer som interagerar med SCM utföras i en separat tråd, oberoende av de åtgärder som sker under initialiseringsfasen.

B visar en algoritm för att korrekt starta en tjänst med hjälp av en hjälptråd.

Handlarfunktion

B visar koden för Handler-funktionen och hjälptrådar. För "Stop" och "Shutdown"-förfrågningar används en algoritm för att korrekt stoppa tjänsten, liknande den som används när en tjänst startas, med den enda skillnaden att istället för parametern SERVICE_START_PENDING skickas parametern SERVICE_STOP_PENDING till SetserviceStatus, och istället för parametern SERVICE_START_PENDING av SERVICE_RUNNING - SERVICE_STOPPED.

Helst bör "Pausa" och "Fortsätt"-förfrågningar också använda detta tillvägagångssätt. En nyfiken läsare kan enkelt implementera det utifrån dessa exempel.

Slutsats

Avslutningsvis vill vi notera att utvecklingen av tjänster inte förändrades med övergången till Windows NT 2000. Tjänster fortsätter att vara en viktig del av programvaran på Windows-plattformen, vilket ger utvecklare ett brett utbud av alternativ.


// Funktion som liknar MessageBox Win32 API int ServerMessageBox(RPC_BINDING_HANDLE h, LPSTR lpszText, LPSTR lpszTitle, UINT fuStyle) ( DWORD dwThreadId; HWINSTA hwinstaSave; HDESK hdeskSave; hWINsta; hdeskSave; hWINsta; aktuella objekt " Fönster station " och "Desktop". GetDesktopWindow(); hwinstaSave = GetProcessWindowStation(); dwThreadId = GetCurrentThreadId(); hdeskSave = GetThreadDesktop(dwThreadId); // Ändra säkerhetskontexten till den // som den anropande RPC-klienten har // och få tillgång till användaren //-objekt "Window station" och "Desktop" SetProcessWindowStation( hwinstaUser); ) SetThreadDesktop(hdeskUser); // Visa ett vanligt textfönster. result = MessageBox(NULL, lpszText, lpszTitle, fuStyle); // Återställ sparade objekt // "Window station" och "Desktop". SetThreadDesktop(hdeskSave); SetProcessWindowStation(hwinstaSave); CloseDesktop(hdeskUser); CloseWindowStation(hwinstaUser); returnera resultat; ) void main() ( SERVICE_TABLE_ENTRY steTable = ( (SERVICENAME, ServiceMain), (NULL, NULL) ); // Upprätta en anslutning med SCM. Inuti denna funktion // tas förfrågningar emot och skickas. StartServiceCtrlDispatcher(steTable); ) void WINAPI ServiceMain (DWORD dwArgc, LPSTR *psArgv) ( // Registrera förfrågningshanteraren omedelbart. hSS = RegisterServiceCtrlHandler(SERVICENAME, ServiceHandler); sStatus.dwCheckPoint = 0; sStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP_STOP_INTUE_USStatus;EACCEPT_INUS; Typ = SERVICE_WIN32_OWN_PROCESS sStatus.dwWaitHint = 0; sStatus.dwWin32ExitCode = NOERROR, funktionen InitService() startas en tråd som rapporterar en gång varje // sekund , att tjänsten håller på att initieras // En händelse skapas för att synkronisera tråden // Efter detta startas en arbetstråd, // för vilken en händelse skapas. hSendStartPending = CreateEvent(NULL, TRUE, FALSE, NULL); HANTERA hSendStartThread; DWORD dwThreadId; hSendStartThread = CreateThread(NULL, 0, SendStartPending, NULL, 0, &dwThreadId); //All serviceinitiering görs här. InitService(); SetEvent(hSendStartPending); if(WaitForSingleObject(hSendStartThread, 2000) != WAIT_OBJECT_0) ( TerminateThread(hSendStartThread, 0); ) CloseHandle(hSendStartPending); CloseHandle(hSendStartThread); hWork = CreateEvent(NULL, TRUE, FALSE, NULL); hServiceThread = CreateThread(NULL, 0, ServiceFunc, 0, 0, &dwThreadId); sStatus.dwCurrentState = SERVICE_RUNNING; SetServiceStatus(hSS, &sStatus); ) // En trådfunktion som skickar meddelanden till SCM // varje sekund att initieringsprocessen pågår. Funktionen // slutar när händelsen hSendStartPending // är inställd. DWORD WINAPI SendStartPending(LPVOID) ( sStatus.dwCheckPoint = 0; sStatus.dwCurrentState = SERVICE_START_PENDING; sStatus.dwWaitHint = 2000; // “Sleep” i 1 sekund. Om efter 1 sekund // händelsen inte har gått in // har händelsen avslutats. tillstånd (tjänstinitiering har inte // avslutats), skicka nästa meddelande, // ställ in det maximala tidsintervallet // till 2 sekunder, så att det finns en tidsmarginal till // nästa meddelande medan (sant) ( SetServiceStatus(hSS, &sStatus); Läsa data, // minnesallokering, etc. void InitService() ( ... ) // Funktion som innehåller tjänstekod. DWORD WINAPI ServiceFunc(LPVOID) ( while (true) ( ​​if (!bPause) ( // Detta innehåller kod som vanligtvis // utför någon form av cykliska operationer... ) if (WaitForSingleObject(hWork, 1000)!=WAIT_TIMEOUT ) break; ) return 0; ) // Begär hanterare från SCM void WINAPI ServiceHandler(DWORD dwCode) ( växel (dwCode) (fall SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: ReportStatusToSCMgr(SERVICE_STOP_PENDORING, 0_ERStop_PENDOR, 0,0,0; , TRUE, FALSE, NULL); hSendStopThread = CreateThread(NULL, 0, SendStopPending, NULL, 0, & dwThreadId); ; CloseHandle(hServiceThread); if(WaitForSingleObject(hSendStopThread, 2000) != WAIT_OBJECT_0) (TerminateThread(hSendStopThread, 0); ) CloseHandle(hSendStopPending;SS, &Status); ha sönder; DWORD WINAPI SendStopPending(LPVOID) ( sStatus.dwCheckPoint = 0; sStatus.dwCurrentState = SERVICE_STOP_PENDING; sStatus.dwWaitHint = 2000; while (true) (SetServiceStatus(hSS, &sPointStatus.bWle); (hSendStopPending, 1000 )! =WAIT_TIMEOUT) sStatus.dwCheckPoint = 0;