Valhalla Legends Archive

Programming => General Programming => .NET Platform => Topic started by: Mephisto on December 23, 2004, 09:08 PM

Title: C# - Invoking Win32 API or...
Post by: Mephisto on December 23, 2004, 09:08 PM
Is there a way to invoke the Win32 with the .NET framework (specifically C#).  I'm trying to create an online method of starting and stopping a service.  Normally to start a service I'd use a Win32 API call to StartService(), but obviously you can't just do that in C# (or I don't know how), so could someone explain to me how I'd do this?  Or if this isn't possible (and even if it is please tell me anyways) is there a way to start a service and stop a service native to .NET?

(btw, forgive me if there've been posts on this already, if so just direct me to them)
Title: Re: C# - Invoking Win32 API or...
Post by: dxoigmn on December 23, 2004, 09:23 PM
http://www.google.com/search?hl=en&q=StartService+C%23+.NET&btnG=Google+Search

Edit: You may also want to look at the System.ServiceProcess namespace on MSDN.
Title: Re: C# - Invoking Win32 API or...
Post by: MyndFyre on December 23, 2004, 10:00 PM
If you wanted to go entirely P/Invoke:

Here is the prototype for CreateService:

SC_HANDLE CreateService(
  SC_HANDLE hSCManager,
  LPCTSTR lpServiceName,
  LPCTSTR lpDisplayName,
  DWORD dwDesiredAccess,
  DWORD dwServiceType,
  DWORD dwStartType,
  DWORD dwErrorControl,
  LPCTSTR lpBinaryPathName,
  LPCTSTR lpLoadOrderGroup,
  LPDWORD lpdwTagId,
  LPCTSTR lpDependencies,
  LPCTSTR lpServiceStartName,
  LPCTSTR lpPassword
);


C# import:

[DllImport("advapi32.dll")]
public static extern IntPtr CreateService(
  IntPtr hSCManager,
  string lpServiceName,
  string lpDisplayName,
  int dwDesiredAccess,
  int dwServiceType,
  int dwStartType,
  int dwErrorControl,
  string lpBinaryPathName,
  string lpLoadOrderGroup,
  [Out] out int lpdwTagId,
  string lpDependencies,
  string lpServiceStartName,
  string lpPassword
);

This is the declaration for the dwAccessRights param:

#define SERVICE_QUERY_CONFIG           0x0001
#define SERVICE_CHANGE_CONFIG          0x0002
#define SERVICE_QUERY_STATUS           0x0004
#define SERVICE_ENUMERATE_DEPENDENTS   0x0008
#define SERVICE_START                  0x0010
#define SERVICE_STOP                   0x0020
#define SERVICE_PAUSE_CONTINUE         0x0040
#define SERVICE_INTERROGATE            0x0080
#define SERVICE_USER_DEFINED_CONTROL   0x0100

#define SERVICE_ALL_ACCESS             (STANDARD_RIGHTS_REQUIRED     | \
                                        SERVICE_QUERY_CONFIG         | \
                                        SERVICE_CHANGE_CONFIG        | \
                                        SERVICE_QUERY_STATUS         | \
                                        SERVICE_ENUMERATE_DEPENDENTS | \
                                        SERVICE_START                | \
                                        SERVICE_STOP                 | \
                                        SERVICE_PAUSE_CONTINUE       | \
                                        SERVICE_INTERROGATE          | \
                                        SERVICE_USER_DEFINED_CONTROL)

I'm not going to change that over to an enum.  I do one for you below, you should be able to figure it out.

To get the IntPtr hSCManager, you need to call OpenSCManager.  C Prototype:

SC_HANDLE OpenSCManager(
  LPCTSTR lpMachineName,
  LPCTSTR lpDatabaseName,
  DWORD dwDesiredAccess
);

C# equiv:

[DllImport("advapi32.dll")]
public static extern IntPtr OpenSCManager(
  string lpMachineName,
  string lpDatabaseName,
  SvcCtrlManagerPrivilegeFlags dwDesiredAccess
);

Also, you'll want to have the right access parameters.  From WinSvc.h:

#define SC_MANAGER_CONNECT             0x0001
#define SC_MANAGER_CREATE_SERVICE      0x0002
#define SC_MANAGER_ENUMERATE_SERVICE   0x0004
#define SC_MANAGER_LOCK                0x0008
#define SC_MANAGER_QUERY_LOCK_STATUS   0x0010
#define SC_MANAGER_MODIFY_BOOT_CONFIG  0x0020

C#:

[Flags]
public enum SvcCtrlManagerPrivilegeFlags
{
  SC_MANAGER_CONNECT = 0x0001
  SC_MANAGER_CREATE_SERVICE = 0x0002
  SC_MANAGER_ENUMERATE_SERVICE = 0x0004
  SC_MANAGER_LOCK = 0x0008
  SC_MANAGER_QUERY_LOCK_STATUS = 0x0010
  SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020
}

Then you want to start the service.  C prototype:

BOOL StartService(
  SC_HANDLE hService,
  DWORD dwNumServiceArgs,
  LPCTSTR* lpServiceArgVectors
);

C# equivalent:

[DllImport("advapi32.dll")]
public static extern bool StartService(
  IntPtr hService,
  int dwNumServiceArgs,
  [MarshalAs(UnmanagedType.LPArray)] string[] lpServiceArgVectors
);


So in total, with the above declarations, you'd want to do:

IntPtr hSCM = OpenSCManager(null, null, SvcCtrlManagerPrivilegeFlags.SC_MANAGER_CREATE_SERVICE);
IntPtr hSvc = CreateService(hSCM, "My Service", "My Service", AccessRightFlags.SERVICE_ALL_ACCESS, ServiceTypes.SERVICE_KERNEL_DRIVER, StartTypes.SERVICE_BOOT_START, ErrorControlTypes.SERVICE_ERROR_NORMAL, "mySvc.exe", out myTags, null, null, null);
bool done = StartService(hSvc, 0, null);


Code is untested and uncompiled, but should generally work as-is.

Constants are declared in WinSvc.h.  If you need it, PM me.