如何在 C# 中编写可以远程调用的 DCOM 服务器? [英] How to write a DCOM server in C# that you can call remotely?

查看:51
本文介绍了如何在 C# 中编写可以远程调用的 DCOM 服务器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定以下 C# 服务器代码来启动 DCOM 服务器:

Given the following C# server code to start a DCOM server:

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 代码 *本地 调用:

Which we assume is compiled as a dll and registered with regasm and then called with the following VBS code *locally:

Dim obj
Set obj = CreateObject( "Test.CMyClass" )
wscript.echo obj.GetDateTime("Current date: ")

现在假设我想在另一台机器上运行这个 vbs 代码并远程调用 DCOM 服务器.我需要改变什么?

Now assume I want to run this vbs code on another machine and call the DCOM server remotely. What do I need to change?

我的问题是:如何用C#编写一个可以远程调用的DCOM服务器?(假设以上所有步骤都已完成)

My question is: How to write a DCOM server in C# that you can call remotely? (Assuming all the above steps have been done)

推荐答案

您可以使用组件服务 MMC 或 DCOMCnfg.exe 对其进行配置以进行远程访问.

You use the Component Services MMC, or DCOMCnfg.exe, to configure it for remote access.

然后您可以使用 CreateObject 的双参数形式创建它.

Then you can create it using the two-argument form of CreateObject.

Set obj = CreateObject( "Test.CMyClass", "SERVERNAME" )

这篇关于如何在 C# 中编写可以远程调用的 DCOM 服务器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆