当然可以!using System; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.ServiceProcess; using System.Threading; using System.Runtime.InteropServices;namespace Test { // // .NET class, interface exposed through DCOM // // exposed COM interface [GuidAttribute(MyService.guidIMyInterface), ComVisible(true)] public interface IMyInterface { string GetDateTime(string prefix); } // exposed COM class [GuidAttribute(MyService.guidMyClass), ComVisible(true)] public class CMyClass: IMyInterface { // Print date & time and the current EXE name public string GetDateTime(string prefix) { Process currentProcess = Process.GetCurrentProcess(); return string.Format("{0}: {1} [server-side COM call executed on {2}]", prefix, DateTime.Now, currentProcess.MainModule.ModuleName); } } // // My hosting Windows service // internal class MyService : ServiceBase { public MyService() { // Initialize COM security Thread.CurrentThread.ApartmentState = ApartmentState.STA; UInt32 hResult = ComAPI.CoInitializeSecurity( IntPtr.Zero, // Add here your Security descriptor -1, IntPtr.Zero, IntPtr.Zero, ComAPI.RPC_C_AUTHN_LEVEL_PKT_PRIVACY, ComAPI.RPC_C_IMP_LEVEL_IDENTIFY, IntPtr.Zero, ComAPI.EOAC_DISABLE_AAA | ComAPI.EOAC_SECURE_REFS | ComAPI.EOAC_NO_CUSTOM_MARSHAL, IntPtr.Zero); if (hResult != 0) throw new ApplicationException( "CoIntializeSecurity failed" + hResult.ToString("X")); } // The main entry point for the process static void Main() { ServiceBase.Run(new ServiceBase[] { new MyService() }); } /// /// On start, register the COM class factory /// protected override void OnStart(string[] args) { Guid CLSID_MyObject = new Guid(MyService.guidMyClass); UInt32 hResult = ComAPI.CoRegisterClassObject( ref CLSID_MyObject, new MyClassFactory(), ComAPI.CLSCTX_LOCAL_SERVER, ComAPI.REGCLS_MULTIPLEUSE, out _cookie); if (hResult != 0) throw new ApplicationException( "CoRegisterClassObject failed" + hResult.ToString("X")); } /// /// On stop, remove the COM class factory registration /// protected override void OnStop() { if (_cookie != 0) ComAPI.CoRevokeClassObject(_cookie); } private int _cookie = 0; // // Public constants // public const string serviceName = "MyService"; public const string guidIMyInterface = "e88d15a5-0510-4115-9aee-a8421c96decb"; public const string guidMyClass = "f681abd0-41de-46c8-9ed3-d0f4eba19891"; } // // Standard installer // [RunInstaller(true)] public class MyServiceInstaller : System.Configuration.Install.Installer { public MyServiceInstaller() { processInstaller = new ServiceProcessInstaller(); serviceInstaller = new ServiceInstaller(); // Add a new service running under Local SYSTEM processInstaller.Account = ServiceAccount.LocalSystem; serviceInstaller.StartType = ServiceStartMode.Manual; serviceInstaller.ServiceName = MyService.serviceName; Installers.Add(serviceInstaller); Installers.Add(processInstaller); } private ServiceInstaller serviceInstaller; private ServiceProcessInstaller processInstaller; } // // Internal COM Stuff // /// /// P/Invoke calls /// internal class ComAPI { [DllImport("OLE32.DLL")] public static extern UInt32 CoInitializeSecurity( IntPtr securityDescriptor, Int32 cAuth, IntPtr asAuthSvc, IntPtr reserved, UInt32 AuthLevel, UInt32 ImpLevel, IntPtr pAuthList, UInt32 Capabilities, IntPtr reserved3 ); [DllImport ("ole32.dll")] public static extern UInt32 CoRegisterClassObject ( ref Guid rclsid, [MarshalAs (UnmanagedType.Interface)]IClassFactory pUnkn, int dwClsContext, int flags, out int lpdwRegister); [DllImport ("ole32.dll")] public static extern UInt32 CoRevokeClassObject (int dwRegister); public const int RPC_C_AUTHN_LEVEL_PKT_PRIVACY = 6; // Encrypted DCOM communication public const int RPC_C_IMP_LEVEL_IDENTIFY = 2; // No impersonation really required public const int CLSCTX_LOCAL_SERVER = 4; public const int REGCLS_MULTIPLEUSE = 1; public const int EOAC_DISABLE_AAA = 0x1000; // Disable Activate-as-activator public const int EOAC_NO_CUSTOM_MARSHAL = 0x2000; // Disable custom marshalling public const int EOAC_SECURE_REFS = 0x2; // Enable secure DCOM references public const int CLASS_E_NOAGGREGATION = unchecked((int)0x80040110); public const int E_NOINTERFACE = unchecked((int)0x80004002); public const string guidIClassFactory = "00000001-0000-0000-C000-000000000046"; public const string guidIUnknown = "00000000-0000-0000-C000-000000000046"; } /// /// IClassFactory declaration /// [ComImport (), InterfaceType (ComInterfaceType.InterfaceIsIUnknown), Guid (ComAPI.guidIClassFactory)] internal interface IClassFactory { [PreserveSig] int CreateInstance (IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject); [PreserveSig] int LockServer (bool fLock); } /// /// My Class factory implementation /// internal class MyClassFactory : IClassFactory { public int CreateInstance (IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject) { ppvObject = IntPtr.Zero; if (pUnkOuter != IntPtr.Zero) Marshal.ThrowExceptionForHR (ComAPI.CLASS_E_NOAGGREGATION); if (riid == new Guid(MyService.guidIMyInterface) || riid == new Guid(ComAPI.guidIUnknown)) { // // Create the instance of my .NET object // ppvObject = Marshal.GetComInterfaceForObject( new CMyClass(), typeof(IMyInterface)); } else Marshal.ThrowExceptionForHR (ComAPI.E_NOINTERFACE); return 0; } public int LockServer (bool lockIt) { return 0; } } } 注册CMD脚本 set EXE_FULL_PATH=%~dp0windowsservice1.exe if not exist %EXE_FULL_PATH% @echo Executable %EXE_FULL_PATH% not present in the current directory! & @goto :EOF installutil /u %EXE_FULL_PATH% installutil %EXE_FULL_PATH% regasm %EXE_FULL_PATH% /codebase REG.EXE ADD HKCR\AppID\{9922b97d-ce4a-4cc8-a26f-4944708e652d} /v LocalService /t REG_SZ /d MyService /f REG.EXE ADD HKCR\CLSID\{F681ABD0-41DE-46C8-9ED3-D0F4EBA19891}\LocalServer32 /ve /t REG_SZ /d %EXE_FULL_PATH% /f REG.EXE DELETE HKCR\CLSID\{F681ABD0-41DE-46C8-9ED3-D0F4EBA19891}\InprocServer32 /f
不过,大部分远过程调用工作都可以使用WebServices来实现,比DCOM简单而且易于开发。
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;
using System.Runtime.InteropServices;namespace Test
{
//
// .NET class, interface exposed through DCOM
// // exposed COM interface
[GuidAttribute(MyService.guidIMyInterface), ComVisible(true)]
public interface IMyInterface
{
string GetDateTime(string prefix);
} // exposed COM class
[GuidAttribute(MyService.guidMyClass), ComVisible(true)]
public class CMyClass: IMyInterface
{
// Print date & time and the current EXE name
public string GetDateTime(string prefix)
{
Process currentProcess = Process.GetCurrentProcess();
return string.Format("{0}: {1} [server-side COM call executed on {2}]",
prefix, DateTime.Now, currentProcess.MainModule.ModuleName);
}
} //
// My hosting Windows service
//
internal class MyService :
ServiceBase
{
public MyService()
{
// Initialize COM security
Thread.CurrentThread.ApartmentState = ApartmentState.STA;
UInt32 hResult = ComAPI.CoInitializeSecurity(
IntPtr.Zero, // Add here your Security descriptor
-1,
IntPtr.Zero,
IntPtr.Zero,
ComAPI.RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
ComAPI.RPC_C_IMP_LEVEL_IDENTIFY,
IntPtr.Zero,
ComAPI.EOAC_DISABLE_AAA
| ComAPI.EOAC_SECURE_REFS
| ComAPI.EOAC_NO_CUSTOM_MARSHAL,
IntPtr.Zero);
if (hResult != 0)
throw new ApplicationException(
"CoIntializeSecurity failed" + hResult.ToString("X"));
} // The main entry point for the process
static void Main()
{
ServiceBase.Run(new ServiceBase[] { new MyService() });
}
///
/// On start, register the COM class factory
///
protected override void OnStart(string[] args)
{
Guid CLSID_MyObject = new Guid(MyService.guidMyClass);
UInt32 hResult = ComAPI.CoRegisterClassObject(
ref CLSID_MyObject,
new MyClassFactory(),
ComAPI.CLSCTX_LOCAL_SERVER,
ComAPI.REGCLS_MULTIPLEUSE,
out _cookie);
if (hResult != 0)
throw new ApplicationException(
"CoRegisterClassObject failed" + hResult.ToString("X"));
}
///
/// On stop, remove the COM class factory registration
///
protected override void OnStop()
{
if (_cookie != 0)
ComAPI.CoRevokeClassObject(_cookie);
}
private int _cookie = 0; //
// Public constants
//
public const string serviceName = "MyService";
public const string guidIMyInterface = "e88d15a5-0510-4115-9aee-a8421c96decb";
public const string guidMyClass = "f681abd0-41de-46c8-9ed3-d0f4eba19891";
} //
// Standard installer
//
[RunInstaller(true)]
public class MyServiceInstaller :
System.Configuration.Install.Installer
{
public MyServiceInstaller()
{
processInstaller = new ServiceProcessInstaller();
serviceInstaller = new ServiceInstaller();
// Add a new service running under Local SYSTEM
processInstaller.Account = ServiceAccount.LocalSystem;
serviceInstaller.StartType = ServiceStartMode.Manual;
serviceInstaller.ServiceName = MyService.serviceName;
Installers.Add(serviceInstaller);
Installers.Add(processInstaller);
}
private ServiceInstaller serviceInstaller;
private ServiceProcessInstaller processInstaller;
} //
// Internal COM Stuff
// ///
/// P/Invoke calls
///
internal class ComAPI
{
[DllImport("OLE32.DLL")]
public static extern UInt32 CoInitializeSecurity(
IntPtr securityDescriptor,
Int32 cAuth,
IntPtr asAuthSvc,
IntPtr reserved,
UInt32 AuthLevel,
UInt32 ImpLevel,
IntPtr pAuthList,
UInt32 Capabilities,
IntPtr reserved3
);
[DllImport ("ole32.dll")]
public static extern UInt32 CoRegisterClassObject (
ref Guid rclsid,
[MarshalAs (UnmanagedType.Interface)]IClassFactory pUnkn,
int dwClsContext,
int flags,
out int lpdwRegister);
[DllImport ("ole32.dll")]
public static extern UInt32 CoRevokeClassObject (int dwRegister);
public const int RPC_C_AUTHN_LEVEL_PKT_PRIVACY = 6; // Encrypted DCOM communication
public const int RPC_C_IMP_LEVEL_IDENTIFY = 2; // No impersonation really required
public const int CLSCTX_LOCAL_SERVER = 4;
public const int REGCLS_MULTIPLEUSE = 1;
public const int EOAC_DISABLE_AAA = 0x1000; // Disable Activate-as-activator
public const int EOAC_NO_CUSTOM_MARSHAL = 0x2000; // Disable custom marshalling
public const int EOAC_SECURE_REFS = 0x2; // Enable secure DCOM references
public const int CLASS_E_NOAGGREGATION = unchecked((int)0x80040110);
public const int E_NOINTERFACE = unchecked((int)0x80004002);
public const string guidIClassFactory = "00000001-0000-0000-C000-000000000046";
public const string guidIUnknown = "00000000-0000-0000-C000-000000000046";
} ///
/// IClassFactory declaration
///
[ComImport (), InterfaceType (ComInterfaceType.InterfaceIsIUnknown),
Guid (ComAPI.guidIClassFactory)]
internal interface IClassFactory
{
[PreserveSig]
int CreateInstance (IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);
[PreserveSig]
int LockServer (bool fLock);
} ///
/// My Class factory implementation
///
internal class MyClassFactory : IClassFactory
{
public int CreateInstance (IntPtr pUnkOuter,
ref Guid riid,
out IntPtr ppvObject)
{
ppvObject = IntPtr.Zero;
if (pUnkOuter != IntPtr.Zero)
Marshal.ThrowExceptionForHR (ComAPI.CLASS_E_NOAGGREGATION);
if (riid == new Guid(MyService.guidIMyInterface)
|| riid == new Guid(ComAPI.guidIUnknown))
{
//
// Create the instance of my .NET object
//
ppvObject = Marshal.GetComInterfaceForObject(
new CMyClass(), typeof(IMyInterface));
}
else
Marshal.ThrowExceptionForHR (ComAPI.E_NOINTERFACE);
return 0;
}
public int LockServer (bool lockIt)
{
return 0;
}
}
}
注册CMD脚本
set EXE_FULL_PATH=%~dp0windowsservice1.exe
if not exist %EXE_FULL_PATH% @echo Executable %EXE_FULL_PATH% not present in the current directory! & @goto :EOF
installutil /u %EXE_FULL_PATH%
installutil %EXE_FULL_PATH%
regasm %EXE_FULL_PATH% /codebase
REG.EXE ADD HKCR\AppID\{9922b97d-ce4a-4cc8-a26f-4944708e652d} /v LocalService /t REG_SZ /d MyService /f
REG.EXE ADD HKCR\CLSID\{F681ABD0-41DE-46C8-9ED3-D0F4EBA19891}\LocalServer32 /ve /t REG_SZ /d %EXE_FULL_PATH% /f
REG.EXE DELETE HKCR\CLSID\{F681ABD0-41DE-46C8-9ED3-D0F4EBA19891}\InprocServer32 /f