Если вы используете следующий код:
[DllImport("advapi32.dll", CharSet=CharSet.Unicode)]
static extern bool StartServiceCtrlDispatcher(IntPtr services);
[DllImport("ntdll.dll", EntryPoint="RtlZeroMemory")]
static extern void ZeroMemory(IntPtr destination, int length);
static bool StartService(){
MySvc svc = new MySvc(); // replace "MySvc" with your service name, of course
typeof(ServiceBase).InvokeMember("Initialize", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
null, svc, new object[]{false});
object entry = typeof(ServiceBase).InvokeMember("GetEntry",
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, svc, null);
int len = Marshal.SizeOf(entry) * 2;
IntPtr memory = Marshal.AllocHGlobal(len);
ZeroMemory(memory, len);
Marshal.StructureToPtr(entry, memory, false);
return StartServiceCtrlDispatcher(memory);
}
[STAThread]
static void Main(){
if(StartService())
return;
Application.Run(new MainWnd()); // replace "MainWnd" with whatever your main window is called
}
Тогда ваш EXE будет работать как служба (если запущена SCM) или как GUI (если запущен любым другим процессом).
По сути, все, что я здесь сделал, используется Отражатель , чтобы выяснить, что делает мясо ServiceBase.Run
, и продублировать его здесь (требуется отражение, потому что оно вызывает частные методы). Причина, по которой мы не вызываем ServiceBase.Run
напрямую, заключается в том, что появляется всплывающее окно с сообщением пользователю , что служба не может быть запущена (если не запущена SCM), и не возвращает ничего, чтобы сообщить код , что служба не может быть запущена.
Поскольку для вызова методов частной платформы используется отражение, оно может работать некорректно в будущих версиях платформы. Предостережение Codor.