如何用 C# 编写可以远程调用的 DCOM 服务器?
Posted
技术标签:
【中文标题】如何用 C# 编写可以远程调用的 DCOM 服务器?【英文标题】:How to write a DCOM server in C# that you can call remotely? 【发布时间】:2014-03-07 13:10:09 【问题描述】:给定以下 C# 服务器代码来启动 DCOM 服务器:
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;
我们假设它被编译为 dll 并使用 regasm
注册,然后使用以下 VBS 代码 *本地调用:
Dim obj
Set obj = CreateObject( "Test.CMyClass" )
wscript.echo obj.GetDateTime("Current date: ")
现在假设我想在另一台机器上运行这个 vbs 代码并远程调用 DCOM 服务器。 我需要改变什么?
我的问题是:如何用C#编写一个可以远程调用的DCOM服务器?(假设以上步骤都已完成)
【问题讨论】:
【参考方案1】:您使用组件服务 MMC 或 DCOMCnfg.exe 对其进行配置以进行远程访问。
然后你可以使用 CreateObject 的两个参数形式来创建它。
Set obj = CreateObject( "Test.CMyClass", "SERVERNAME" )
【讨论】:
我确实尝试过 - 但出现错误。也许我做错了什么。您能否详细说明我需要遵循的步骤? @hawkeye,您应该查看错误号 - 它们很有意义。以上是关于如何用 C# 编写可以远程调用的 DCOM 服务器?的主要内容,如果未能解决你的问题,请参考以下文章