zoukankan      html  css  js  c++  java
  • 如何用C#编写DCOM服务器

    How to write a DCOM server in C# 如何用C#编写DCOM服务器

    先讲讲.net Remoting与DCOM的区别:.net Remoting 是在DCOM等基础上发展起来的一种技术,它的主要目的是实现跨平台、跨语言、穿透企业防火墙。DCOM是通过TCP/IP通道安全的进程间通信,而.NET remoting 不是。任何进程包括windows服务都能寄宿在DCOM服务器中。

    如果你已经十分清楚地知道了COM的话,可以参考下面的几点加深你对DCOM的了解。

    1) Your server process will expose a COM class factory that would just create your .NET object.

        你的DCOM服务器进程应该暴露一个COM类工厂以便于创建.net对象

    2) In COM you register the class factory using the standard CoRegisterClassObjects API 。

        在COM中尼应该使用标准的API(CoRegisterClassObjects函数)注册类工厂。

    3) Make sure you call CoInitializeSecurity on your first process, for example to allow only Administrators to call in 。

       确认在第一个进程中调用CoInitializeSecurity函数,例如尽允许在具有管理员的主机上调用。

    4) Register your .NET assemblies with REGASM.EXE. Make sure your .NET class is visible through COM so CCW can be created around it (more details in MSDN on COM Interop section).

        使用REGASM.EXE工具注册.net汇编程序,确认你的.netleu通过COM组件后可见,以便于可以创建CCW。

    5) Remove the auto-generated InprocServer32 key after registration (REGASM puts it there but we are going out-of-proc)

      完成注册后移除自动产生的InprocServer32 key。

    6) Add the standard LocalServer32 / AppID registry keys.

       添加标准的LocalServer32 / AppID的注册表键值。

    view plaincopy to clipboardprint?
    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;  
      }   
     }  

    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批处理脚本:

    view plaincopy to clipboardprint?
    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 
    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 

    And a test VBS script that will exercise our service from a separate process obviously:

    通过一个独立进程的VBS测试脚本来实践我们的服务

    view plaincopy to clipboardprint?
    Dim obj  
    Set obj = CreateObject( "Test.CMyClass" )  
    wscript.echo obj.GetDateTime("Current date: ") 
    Dim obj
    Set obj = CreateObject( "Test.CMyClass" )
    wscript.echo obj.GetDateTime("Current date: ")

    One more comment: The code above allows everybody to call into the process. This is probably not very useful since you might want to allow only administrators to call into your service. There is a solution though: all you have to do is to pass a certain security descriptor to CoInitializeSecurity that will allow only certain classes of users to call into the process. This is actually not very hard, and I'll probably post a sample code in the future. Now I have to get back to work, so see you for the next time!

    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/libicong00/archive/2010/12/02/6049061.aspx

  • 相关阅读:
    日报9.4
    日报9.3
    低级错误整理
    树状数组求逆序对 笔记与思路整理
    st表、树状数组与线段树 笔记与思路整理
    Luogu P1098 字符串的展开
    Luogu P1816 忠诚
    jmeter cookie管理器 使用方法---新手学习记录1
    kali nessus 安装插件失败解决方法
    https tomcat 证书搭建
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2453224.html
Copyright © 2011-2022 走看看