Napisałem małą usługę, która działa jako lokalny serwer sieciowy. Aby napisać usługę, postępowałem zgodnie z tutorial on MSDN, jak napisać usługę przy użyciu klasy ServiceBase
.Usługa powoduje błąd SCM "zgłosiło niepoprawny stan bieżący 0"
Po zarejestrowaniu się i uruchomieniu usługi wyświetlane są komunikaty o błędach, jak pokazano poniżej. Dostaję dokładnie dwa z tych komunikatów o błędach na początku i na przystanku serwisowym. (Przykład = nazwa usługi).
Przykład ten serwis poinformował nieprawidłowy stan obecny 0.
Tutaj minimalną próbkę moich usług ze wszystkimi odpowiednimi częściami. Kod rozpoczyna się od definicji enum i struct, który został podany w poradniku MSDN:
public enum ServiceState
{
SERVICE_STOPPED = 0x00000001,
SERVICE_START_PENDING = 0x00000002,
SERVICE_STOP_PENDING = 0x00000003,
SERVICE_RUNNING = 0x00000004,
SERVICE_CONTINUE_PENDING = 0x00000005,
SERVICE_PAUSE_PENDING = 0x00000006,
SERVICE_PAUSED = 0x00000007,
}
[StructLayout(LayoutKind.Sequential)]
public struct ServiceStatus
{
public long dwServiceType;
public ServiceState dwCurrentState;
public long dwControlsAccepted;
public long dwWin32ExitCode;
public long dwServiceSpecificExitCode;
public long dwCheckPoint;
public long dwWaitHint;
};
Po tym kodzie serwisowym napisałem, sprowadza się do odpowiednich części:
namespace example
{
public partial class Service : ServiceBase
{
public Service()
: base()
{
this.ServiceName = "ExampleService";
this.AutoLog = false;
this.CanStop = true;
this.CanShutdown = false;
this.CanPauseAndContinue = false;
this.CanHandlePowerEvent = false;
this.CanHandleSessionChangeEvent = false;
}
protected override void OnStart(string[] args)
{
try {
SetServiceState(ServiceState.SERVICE_START_PENDING, 100000);
// ... initialise and start...
SetServiceState(ServiceState.SERVICE_RUNNING);
} catch (System.Exception ex) {
SetServiceState(ServiceState.SERVICE_STOPPED);
}
}
protected override void OnStop()
{
SetServiceState(ServiceState.SERVICE_STOP_PENDING, 100000);
// ... stop service ...
SetServiceState(ServiceState.SERVICE_STOPPED);
}
private void SetServiceState(ServiceState state, int waitHint = 0)
{
ServiceStatus serviceStatus = new ServiceStatus();
serviceStatus.dwCurrentState = state;
serviceStatus.dwWaitHint = waitHint;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
}
[DllImport("advapi32.dll", SetLastError=true)]
private static extern bool SetServiceStatus(IntPtr handle, ref ServiceStatus serviceStatus);
}
}
głównego punktu wejścia jest proste, jak to:
static void Main(string[] args)
{
ServiceBase.Run(new Service());
}
jak widać, liczba komunikatów o błędach dopasowuje liczbę SetServiceState
połączeń. Jeśli dodaję dodatkowe takie połączenia, liczba komunikatów o błędach odpowiednio wzrośnie.
Zakładam więc, że cały problem jest gdzieś w drodze, którą nazywam API SetServiceStatus
, ale obecnie nie widzę problemu.
Czy możesz zauważyć problem?
Czy to jest poprawny sposób na zbudowanie usługi przy użyciu C# i .NET?
Świetnie, dziękuję, to rozwiązało problem. Zazwyczaj zdaję sobie sprawę z tego, jak zła jest dokumentacja MSDN, ale tutaj po prostu założyłem, że definicja struktury z przykładu jest prawidłowa. Masz również rację, ręczne aktualizacje statusu nie są naprawdę konieczne. Uruchomienie mojego kodu zajęło dużo czasu w pierwszej wersji, ale przeniosłem wszystko w wątku, ponieważ wynik niektórych z tych długich procesów nie ma znaczenia dla uruchomienia. Świetny wpis na blogu, tylko formatowanie listy krok po kroku sprawiło, że prawie poczułam ból głowy ;-). – Flovdis
Świetnie, zadziałało to dla mnie. Nie da się policzyć, ile błędów ma MSDN ... to była jedna z nieskończonych liczb ... – Fabiano
Wielkie dzięki, Rainer - użyłem przykładowego kodu Microsoftu do stworzenia usługi i od razu trafiłem w ten problem. Dodałem również komentarz do ich strony tutaj (https://technet.microsoft.com/en-us/library/cc756305(v=ws.10).aspx), wskazując tutaj swoje rozwiązanie. – Rich