用C#编写贰个经过外的COM组件

本身在从前的壹篇文章《COM互操作 – 在VB 脚本里面使用.NET类型》里面写过哪些在COM客户端程序里面使用.NET组件,然则那一个.NET组件都属于进程内的零件,即COM客户端供给将CL汉兰达和.NET组件都加载进自身进度的内存空间里面才能采用。上二遍在MSDN汉语论坛上观察有网民问怎么使用C#编写1个历程外的COM组件,由于在采纳re瓦斯m.exe注册.NET组件的时候,regasm.exe将.NET组件里面宣布的COM可知的项目对应CLSID的键值里丰裕了InprocServer32项,并且设置值为mscoree.dll。那也算得,.NET的暗许完结强制了我们只辛亏COM里面激活进度内的.NET组件,不过怎么着用.NET完毕进程外的机件呢?难道真的要大家写三个新的COM程序来Host CLOdyssey?

答案是不是认的,那里是其余贰个替代方案,你须要完毕上面这一个步骤:

1.       在C#代码里面本人完成2个ClassFactory,用来激活我们的Com可知的(Com Visible)类型。

二.       调用COM API CoRegisterClassObject将大家协调的ClassFactory注册在COMCurry面,以便监听COM的激活申请。

三.       COM端使用完结之后,能够经过调用CoRevokeClassObject撤消大家ClassFactory在COMCurry面包车型客车登记。

肆.       若是大家的COM客户端是C++编写的话,并且选取前绑定接口的主意使用大家的Com可知(Com Visible)类型的话,为了能够将接口指针跨越进度边界传输,你还亟需将.NET
Assembly生成的Tlb文件注册,向COM库注册列集(马尔斯haling)接口的艺术。

NET 代码

TestComVisibleClass.cs

1. using System;

2. using System.Runtime.InteropServices;

3. using System.Windows.Forms;

4.

5. namespace TestComServer

6. {

7.     internal static class ComHelperClass

8.     {

9.         public const string s_IID_ITestComVisible = "C66C0654-49AE-4f2e-8EDA-BD01C8259C20";

10.         public const string s_CLSID_TestComVisibleClass = "12D783BB-33BF-4973-B38B-2A8F0BA926E4";

11.         public static readonly Guid IID_ITestComVisible = new Guid(s_IID_ITestComVisible);

12.         public static readonly Guid CLSID_TestComVisibleClass = new Guid(s_CLSID_TestComVisibleClass);

13.

14.         public const string s_IID_IClassFactory = "00000001-0000-0000-C000-000000000046";

15.         public static readonly Guid IID_IClassFactory = new Guid("00000001-0000-0000-C000-000000000046");

16.         public static readonly Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");

17.

18.         [DllImport("ole32.dll")]

19.         public static extern int CoRegisterClassObject(

20.             [MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,

21.             [MarshalAs(UnmanagedType.IUnknown)] object pUnk,

22.             uint dwClsContext,

23.             uint flags,

24.             out uint lpdwRegister);

25.

26.         [DllImport("ole32.dll")]

27.         public static extern int CoRevokeClassObject(uint dwRegister);

28.

29.         [DllImport("ole32.dll")]

30.         public static extern int CoInitializeSecurity(

31.          IntPtr securityDescriptor,

32.          Int32 cAuth,

33.          IntPtr asAuthSvc,

34.          IntPtr reserved,

35.          UInt32 AuthLevel,

36.          UInt32 ImpLevel,

37.          IntPtr pAuthList,

38.          UInt32 Capabilities,

39.          IntPtr reserved3);

40.

41.         public const int RPC_C_AUTHN_LEVEL_PKT_PRIVACY = 6; // Encrypted DCOM communication

42.         public const int RPC_C_IMP_LEVEL_IDENTIFY = 2; // No impersonation really required

43.         public const int CLSCTX_LOCAL_SERVER = 4;

44.         public const int REGCLS_MULTIPLEUSE = 1;

45.         public const int EOAC_DISABLE_AAA = 0x1000; // Disable Activate-as-activator

46.         public const int EOAC_NO_CUSTOM_MARSHAL = 0x2000; // Disable custom marshalling

47.         public const int EOAC_SECURE_REFS = 0x2;   // Enable secure DCOM references

48.         public const int CLASS_E_NOAGGREGATION = unchecked((int)0x80040110);

49.         public const int E_NOINTERFACE = unchecked((int)0x80004002);

50.

51.     }

52.

53.     [ComVisible(true)]

54.     [Guid(ComHelperClass.s_IID_ITestComVisible)]

55.     public interface ITestComVisible

56.     {

57.         [DispId(1)]

58.         string TestProperty { get; set; }

59.

60.         [DispId(2)]

61.         void TestMethod();

62.     }

63.

64.     [ComVisible(true)]

65.     [Guid(ComHelperClass.s_CLSID_TestComVisibleClass)]

66.     public class TestComVisibleClass : ITestComVisible

67.     {

68.         public string TestProperty { get; set; }

69.

70.         public void TestMethod()

71.         {

72.             MessageBox.Show("Test Method");

73.         }

74.     }

75.

76.     // 类厂

77.     [

78.      ComImport,

79.      InterfaceType(ComInterfaceType.InterfaceIsIUnknown),

80.      Guid(ComHelperClass.s_IID_IClassFactory)

81.     ]

82.     internal interface IClassFactory

83.     {

84.         [PreserveSig]

85.         int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);

86.

87.         [PreserveSig]

88.         int LockServer(bool fLock);

89.     }

90.

91.     internal class ComClassFactory : IClassFactory

92.     {

93.         #region IClassFactory Members

94.

95.         public int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject)

96.         {

97.             ppvObject = IntPtr.Zero;

98.

99.             if (pUnkOuter != IntPtr.Zero)

100.                 Marshal.ThrowExceptionForHR(ComHelperClass.CLASS_E_NOAGGREGATION);

101.

102.             if (riid == ComHelperClass.IID_ITestComVisible ||

103.                  riid == ComHelperClass.IID_IUnknown)

104.             {

105.                 ppvObject = Marshal.GetComInterfaceForObject(

106.                     new TestComVisibleClass(), typeof(ITestComVisible));

107.             }

108.             else

109.                 Marshal.ThrowExceptionForHR(ComHelperClass.E_NOINTERFACE);

110.

111.             return 0; // S_OK

112.         }

113.

114.         public int LockServer(bool fLock)

115.         {

116.             return 0; // S_OK

117.         }

118.

119.         #endregion

120.     }

121. }

 

Program.cs

1. using System;

2. using System.Windows.Forms;

3. using System.Runtime.InteropServices;

4.

5. namespace TestComServer

6. {

7.     static class Program

8.     {

9.         private static uint m_ComCookie = 0;

10.

11.         /// <summary>

12.         /// The main entry point for the application.

13.         /// </summary>

14.         [STAThread]

15.         static void Main()

16.         {

17.             Application.EnableVisualStyles();

18.             Application.SetCompatibleTextRenderingDefault(false);

19.

20.             RegisterDcomServer();

21.

22.             Application.ApplicationExit += new EventHandler(Application_ApplicationExit);

23.             Application.Run(new Form1());

24.         }

25.

26.         static void Application_ApplicationExit(object sender, EventArgs e)

27.         {

28.             RevokeDcomServer();

29.         }

30.

31.         private static void RegisterDcomServer()

32.         {

33.             // 做一些安全检查,确保只有一些有权限的人才能调用你的C# Dcom组件

34.             // 如果你对安全性不关心的话,可以删除下面的语句

35.             int hr = ComHelperClass.CoInitializeSecurity(

36.                 IntPtr.Zero, // 这里要输入你的安全描述符

37.                 -1,

38.                 IntPtr.Zero,

39.                 IntPtr.Zero,

40.                 ComHelperClass.RPC_C_AUTHN_LEVEL_PKT_PRIVACY,

41.                 ComHelperClass.RPC_C_IMP_LEVEL_IDENTIFY,

42.                 IntPtr.Zero,

43.                 ComHelperClass.EOAC_DISABLE_AAA | ComHelperClass.EOAC_SECURE_REFS | ComHelperClass.EOAC_NO_CUSTOM_MARSHAL,

44.                 IntPtr.Zero);

45.             if (hr != 0)

46.                 Marshal.ThrowExceptionForHR(hr);

47.

48.             hr = ComHelperClass.CoRegisterClassObject(

49.                 ComHelperClass.CLSID_TestComVisibleClass,

50.                 new ComClassFactory(),

51.                 ComHelperClass.CLSCTX_LOCAL_SERVER,

52.                 ComHelperClass.REGCLS_MULTIPLEUSE,

53.                 out m_ComCookie);

54.             if (hr != 0)

55.                 Marshal.ThrowExceptionForHR(hr);

56.         }

57.

58.         private static void RevokeDcomServer()

59.         {

60.             if (m_ComCookie != 0)

61.                 ComHelperClass.CoRevokeClassObject(m_ComCookie);

62.         }

63.     }

64. }

登记表代码

1. Windows Registry Editor Version 5.00

2.

3. [HKEY_CLASSES_ROOT"TypeLib"{9903F14C-12CE-4c99-9986-2EE3D7D588A8}]

4.

5. [HKEY_CLASSES_ROOT"TypeLib"{9903F14C-12CE-4c99-9986-2EE3D7D588A8}"1.0]

6. @="TestComServer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"

7.

8. [HKEY_CLASSES_ROOT"TypeLib"{9903F14C-12CE-4c99-9986-2EE3D7D588A8}"1.0"0]

9.

10. [HKEY_CLASSES_ROOT"TypeLib"{9903F14C-12CE-4c99-9986-2EE3D7D588A8}"1.0"0"win32]

11. @="D:""Workspace""Forum""Test""TestComServer""bin""Debug""TestComServer.tlb"

12.

13. [HKEY_CLASSES_ROOT"TypeLib"{9903F14C-12CE-4c99-9986-2EE3D7D588A8}"1.0"FLAGS]

14. @="0"

15.

16. [HKEY_CLASSES_ROOT"TypeLib"{9903F14C-12CE-4c99-9986-2EE3D7D588A8}"1.0"HELPDIR]

17.

18. [HKEY_CLASSES_ROOT"Interface"{C66C0654-49AE-4f2e-8EDA-BD01C8259C20}]

19.

20. [HKEY_CLASSES_ROOT"Interface"{C66C0654-49AE-4f2e-8EDA-BD01C8259C20}"ProxyStubClsid]

21. @="{00020424-0000-0000-C000-000000000046}"

22.

23. [HKEY_CLASSES_ROOT"Interface"{C66C0654-49AE-4f2e-8EDA-BD01C8259C20}"ProxyStubClsid32]

24. @="{00020424-0000-0000-C000-000000000046}"

25.

26. [HKEY_CLASSES_ROOT"Interface"{C66C0654-49AE-4f2e-8EDA-BD01C8259C20}"TypeLib]

27. "Version"="1.0"

28. @="{9903F14C-12CE-4c99-9986-2EE3D7D588A8}"

29.

30. [HKEY_CLASSES_ROOT"CLSID"{12D783BB-33BF-4973-B38B-2A8F0BA926E4}]

31. @="TestComServer.TestComVisibleClass"

32.

33. [HKEY_CLASSES_ROOT"CLSID"{12D783BB-33BF-4973-B38B-2A8F0BA926E4}"Implemented Categories]

34.

35. [HKEY_CLASSES_ROOT"CLSID"{12D783BB-33BF-4973-B38B-2A8F0BA926E4}"Implemented Categories"{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}]

36.

37. [HKEY_CLASSES_ROOT"CLSID"{12D783BB-33BF-4973-B38B-2A8F0BA926E4}"LocalServer32]

38. @="D:""Workspace""Forum""Test""TestComServer""bin""Debug""TestComServer.exe"

39.

40. [HKEY_CLASSES_ROOT"CLSID"{12D783BB-33BF-4973-B38B-2A8F0BA926E4}"ProgId]

41. @="TestComServer.TestComVisibleClass"

 

客户端C++代码

1. // TestComClient.cpp : Defines the entry point for the console application.

2. //

3.

4. #include "stdafx.h"

5. #include <windows.h>

6. #import "D:"Workspace"Forum"Test"TestComServer"bin"Debug"TestComServer.tlb" no_namespace, named_guids

7.

8. int _tmain(int argc, _TCHAR* argv[])

9. {

10.    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

11.    assert(SUCCEEDED(hr));

12.

13.    CLSID clsid;

14.    hr = ::CLSIDFromProgIDEx(TEXT("TestComServer.TestComVisibleClass"), &clsid);

15.    assert(SUCCEEDED(hr));

16.   

17.     MULTI_QI mq;

18.    mq.pIID = &IID_ITestComVisible;

19.    mq.pItf = NULL;

20.    mq.hr = S_OK;

21.    hr = ::CoCreateInstanceEx(clsid, NULL, CLSCTX_LOCAL_SERVER, NULL, 1, &mq);

22.    assert(SUCCEEDED(hr));

23.

24.    ITestComVisible *pIt = (ITestComVisible *)mq.pItf;

25.    pIt->TestMethod();

26.    pIt->Release();

27.

28.     CoUninitialize();

29.    return 0;

30. }

 

除此以外壹种客户端,使用VB
Script代码

set obj = CreateObject("TestComServer.TestComVisibleClass")  

obj.TestMethod() 

 

后日急着回家,下一篇文章再解释代码里面包车型地铁情致。

相关文章