Windows Dienst entwickeln



  • heyho,

    ich habe mir einen kleinen Chat (Server + multiple Clients) geschrieben,
    welcher berim heutigen Testlauf in der Schule xD auch recht gut funkionierte.
    allerdings läut dieser in einem Konsolenprogramm in einer Endlosschleife -> while(true)...

    Zum Beenden habe ich also per signal einen Handler angemeldet, der bei SIGINT, SIGABRT und SIGTERM alle sockets schließt und WSACleanup aufruft.

    klickt man oben auf das Kreuz und schließt somit die Konsole, findet das nicht statt.
    offensichtlich wird trotzdem alles korrekt beendet, da trotzdem alle verbindung getrennt wurden.

    allerdings erscheint mir das unsauber und da kam mir die Idee einen Dienst daraus zu machen. (Apache macht das ja auch so xD)

    Die Frage ist nun, wie schreibt man einen Dienst.
    Der erste Post, der mir in der Sufu entgegenhüpfte (mit Titel "Windows Dienst [irgendwas kA]") war nicht sehr hilfreich, da der dortige Fragesteller
    letzten Endes af normale Windows-Programm ohne Fenster verwiesen wurde...

    Das Beispiel in der MSDN ist auch etwas seltsam, da ich nicht genau nachvollziehen kann, wozu ich diese Sample.mc brauche...
    Und wie ich im MSVC Pro 2008 ein Win32-Dienst-Projekt erstellen kann, ist mir auch unklar.
    Aus Apache würd ich einfach schließen, dass es eine normale Anwendung ist...
    Im MSDN Beispiel ist dies eine Konsolen-Anwendung (mit _tmain als Einsprungpunkt)...
    aber wie ist das dann, wenn das Prog vom SCM gestartet wird? wird dann keine Konsole erzeugt? weil das wäre ja auch wieder nervig, wenn man einen Dienst mit Konsolenfenster hätte xD

    also zusammengefasst:
    -> wie erstellt man im MSVC 2008 Pro ein Win32-Dienst-Projekt? (nicht CLR oder so)
    -> wenn normale Win32-Anwendung: Windows oder Konsole?
    -> wozu brauche ich eine *.mc-Datei, bzw. brauche ich diese reine Resourcen-DLL?
    -> gibt es iwo bessere Anleitungen, auf die ihr mich verweisen könnt?

    ich bedanke mich schonmal

    MfG DrakoXP



  • Zum Beenden habe ich also per signal einen Handler angemeldet, der bei SIGINT, SIGABRT und SIGTERM alle sockets schließt und WSACleanup aufruft.

    klickt man oben auf das Kreuz und schließt somit die Konsole, findet das nicht statt.

    Dann verwende einfach SetConsoleCtrlHandler() stattdessen. Damit kannst du Ctrl+C, Break, Fenster-schliessen, Logoff und Shutdown behandeln. Feine Sache 🙂

    -> wozu brauche ich eine *.mc-Datei, bzw. brauche ich diese reine Resourcen-DLL?

    Die .mc Datei brauchst du nur, wenn du Einträge ins EventLog schreiben willst, und dabei Platz sparen. Das .mc File ist dann der sog. "Message Catalog", enthält also alle Einträge die du schreiben möchtest.
    -> würde ich nicht machen, ist nur unnötig viel Aufwand (man muss das .mc File durch den Message-Catalog-Compiler jagen, und dann den Katalog beim Registrieren des Service auch noch extra im System registrieren).

    -> wenn normale Win32-Anwendung: Windows oder Konsole?

    Ganz klar Konsole!

    [quote]gibt es iwo bessere Anleitungen, auf die ihr mich verweisen könnt?[\quote]
    Pfu, jo, gibt einige Beispiel-Codes im Netz.
    Such vielleicht mal nach "Windows Service StartServiceCtrlDispatcher Sample" (ohne die "").

    wie erstellt man im MSVC 2008 Pro ein Win32-Dienst-Projekt? (nicht CLR oder so)

    Die Einfachste Variante ist, ein neues ATL COM Projekt zu machen:

    New Project... -> ATL -> ATL Project -> OK
    Und dann unter "Application Settings" als "Server Type" einfach "Service (EXE)" wählen.
    -> Finish

    (Die Option "attributed" - falles es die im 2008er überhaupt nocht gibt - solltest du *nicht* verwenden - die ist nämlich im 2005er schon deprecated)

    Die COM-Klasse die dabei automatisch erstellt wird ist zwar unnötiger Ballast, dafür musst du keine einzige Zeile selbst schreiben was die nötige Interaktion mit dem Service-Control-Manager angeht.

    Das erzeugte Grundgerüst enthält dann eine "Module" Klasse. In dieser überschreibst du zwei Funktionen der Basisklasse:

    HRESULT XyzModule::PreMessageLoop(int nShowCmd)
    {
        return __super::PreMessageLoop(nShowCmd);
    }
    
    HRESULT XyzModule::PostMessageLoop()
    {
        return __super::PostMessageLoop();
    }
    

    Was du für __super einsetzen musst, musst du im generierten Code nachgucken. Müsste CAtlServiceModuleT<X, Y> sein, wobei X die XyzModule Klasse ist, und Y irgendeine ID.

    In PreMessageLoop schreibst du den Code rein um dein Service zu *starten* (-> hier musst du u.U. nen Worker-Thread erzeugen), und in PostMessageLoop den Code um dein Service zu stoppen.

    ----

    Sonst gäbe es noch die Möglichkeit eine ganz normale Konsolenapplikation zu schreiben, und ein Tool zu verwenden, welches sich selbst als Service einträgt, das dann deine Konsolenapplikation startet (und mit Ctrl+C wieder stoppt).



  • ok, danke, das hilft mir schonmal zum Teil weiter 😉

    allerdings bin ich eben kein Freund von CLR, MFC, ATL usw., weshalb ich eben eine native WinAPI-Lösung anstrebe.
    aber deine ersten Hinweise helfen mir schonmal weiter 😉

    MfG DrakoXP


  • Mod



  • Richtig.

    Und sogar den CreateService Call kann man sich sparen, wenn man einfach das Commandline-Tools "sc" verwendet um das Service zu registrieren.


Anmelden zum Antworten