[ACCEPTED]-How to write c# service that I can also run as a winforms program?-service
You basically have two choices. Either expose 9 an API on the service which you can then 8 call from the UI app OR enable the service 7 to run either as a winforms app or a service.
The 6 first option is pretty easy - use remoting 5 or WCF to expose the API.
The second option 4 can be achieved by moving the "guts" of 3 your app into a separate class then create 2 a service wrapper and a win-forms wrapper 1 that both call into your "guts" class.
static void Main(string[] args)
{
Guts guts = new Guts();
if (runWinForms)
{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
FormWrapper fw = new FormWrapper(guts);
System.Windows.Forms.Application.Run(fw);
}
else
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new ServiceWrapper(guts) };
ServiceBase.Run(ServicesToRun);
}
}
If you use the below code:
[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
}
Then your EXE 15 will run as either a service (if launched 14 by the SCM) or as a GUI (if launched by 13 any other process).
Essentially, all I've 12 done here is used Reflector to figure out what the 11 meat of ServiceBase.Run
does, and duplicate it here (reflection 10 is required, because it calls private methods). The 9 reason for not calling ServiceBase.Run
directly is that 8 it pops up a message box to tell the user that 7 the service cannot be started (if not launched 6 by the SCM) and doesn't return anything 5 to tell the code that the service cannot be 4 started.
Because this uses reflection to 3 call private framework methods, it may not 2 function correctly in future revisions of 1 the framework. Caveat codor.
Create a new winforms app the references 1 the assembly of your service.
See Am I running as a service for some further useful information.
The 3 most important thing covered is how to reliably 2 determine whether we are running interactively 1 or via a service.
you have to implement a separate process 4 that can communicate with your service. While 3 it is possible on XP and earlier systems 2 to have a service showing an UI, that's 1 no longer possible on Vista and later.
Another possibility is to NOT use a service, but 6 to use an application which resides in the 5 Taskbar (think Roxio Drag-to-Disc, & most 4 likely your Anti-virus software lives down 3 there) which has an icon down by the clock, which 2 launches a menu, when it is right-clicked, and 1 a UI when double-clicked.
If your service is modulated properly, you 6 could host the service either in a executable 5 as a service, or with an executable with 4 gui for the test. We use this method with 3 our service too, the standalone service-executable 2 hosts the service in productive environment, but 1 we have a console-app for hosting the service, too.
Separate your code into different components: one 11 component to manage the service aspects 10 and one to perform the actual business logic. Create 9 and interact with the business logic from 8 the service component. For testing (of 7 your business logic) you can create a WinForm 6 or console application that uses the business 5 logic component without the service component. Better 4 yet, use a unit testing framework for the 3 bulk of your testing. Many of the methods 2 in the service component will undoubtedly 1 be unit testable as well.
If you encapsulate your business logic in 11 service classes and then use a factory pattern 10 to create those services, you can use the 9 same set of services for a desktop application 8 (desktop factory) and as web services (host 7 in WCF).
Service definition:
[ServiceContract]
public interface IYourBusinessService
{
[OperationContract]
void DoWork();
}
public class YourBusinessService : IYourBusinessService
{
public void DoWork()
{
//do some business logic here
}
}
Factory for 6 desktop WinForms to get at services to do 5 business:
public class ServiceFactory
{
public static IYourBusinessService GetService()
{
//you can set any addition info here
//like connection string for db, etc.
return new YourBusinessService();
}
}
You host this either with the WCF 4 ServiceHost class, or in IIS. Both allow 3 you the ability to specify how to instantiate 2 each instance of the service so that you 1 can do initialization like connection strings, etc.
You can create the service to call another 4 executable with a command line argument 3 so it is run without the form. When that 2 exe is called without the command line argument 1 it shows the form and act as normal.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.