2014-03-07 108 views
-1

下面的C#服務器代碼啓動DCOM服務器:如何在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") 
+0

我確實嘗試過 - 但遇到了錯誤。也許我做錯了什麼。你能否擴展我需要遵循的步驟? – hawkeye

+0

@hawkeye,你應該查看錯誤號 - 它們是有意義的。 – Ben