c#进程外Com服务(exe)编写调用

网上有些进程外的一些资料,但有些简单,研究了两天写了demo,可利用这种方式解决64位的程序调用32位的dll等问题,但注意方法参数不能含有IntPtr,因为指针跨进程是无效的,每个进程都有自己的内存区域

 一.编写外部Com服务exe

    1.首先新建一个winform的应用程序,并设置com程序集可见


2.编写com类 

    编写com接口,guid可利用vs的工具生成,代码设置com接口的可视,实现接口后,编写com工厂启用com


  

internal static class ComHelperClass
    {
        public const string s_IID_ITestComVisible = "C66C0654-49AE-4f2e-8EDA-BD01C8259C20";
        public const string s_CLSID_TestComVisibleClass = "12D783BB-33BF-4973-B38B-2A8F0BA926E4";
        public static readonly Guid IID_ITestComVisible = new Guid(s_IID_ITestComVisible);
        public static readonly Guid CLSID_TestComVisibleClass = new Guid(s_CLSID_TestComVisibleClass);

        public const string s_IID_IClassFactory = "00000001-0000-0000-C000-000000000046";
        public static readonly Guid IID_IClassFactory = new Guid("00000001-0000-0000-C000-000000000046");
        public static readonly Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");

        [DllImport("ole32.dll")]
        public static extern int CoRegisterClassObject(
            [MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
            [MarshalAs(UnmanagedType.IUnknown)] object pUnk,
            uint dwClsContext,
            uint flags,
            out uint lpdwRegister);

        [DllImport("ole32.dll")]
        public static extern int CoRevokeClassObject(uint dwRegister);

        [DllImport("ole32.dll")]
        public static extern int CoInitializeSecurity(
         IntPtr securityDescriptor,
         Int32 cAuth,
         IntPtr asAuthSvc,
         IntPtr reserved,
         UInt32 AuthLevel,
         UInt32 ImpLevel,
         IntPtr pAuthList,
         UInt32 Capabilities,
         IntPtr reserved3);

        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);
 }

    [ComVisible(true)]
    [Guid(ComHelperClass.s_IID_ITestComVisible)]
    public interface ITestComVisible
    {
        [DispId(1)]
        string TestProperty { get; set; }

        [DispId(2)]

        void TestMethod();

      //可扩展相应的方法接口,并在TestComVisibleClass 实现

    }
    [ComVisible(true)]
    [Guid(ComHelperClass.s_CLSID_TestComVisibleClass)]
    public class TestComVisibleClass : ITestComVisible
    {
        public string TestProperty { get; set; }

        public void TestMethod()
        {
            MessageBox.Show("我是32");
        }
    }
    // 类厂
    [
     ComImport,
     InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
     Guid(ComHelperClass.s_IID_IClassFactory)
    ]
    internal interface IClassFactory
    {
        [PreserveSig]
        int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);
        [PreserveSig]
        int LockServer(bool fLock);
    }
    internal class ComClassFactory : IClassFactory
    {
        #region IClassFactory Members

        public int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject)
        {
            ppvObject = IntPtr.Zero;
            if (pUnkOuter != IntPtr.Zero)
                Marshal.ThrowExceptionForHR(ComHelperClass.CLASS_E_NOAGGREGATION);
            if (riid == ComHelperClass.IID_ITestComVisible ||
                 riid == ComHelperClass.IID_IUnknown)
            {
                ppvObject = Marshal.GetComInterfaceForObject(
                    new TestComVisibleClass(), typeof(ITestComVisible));
            }
            else
                Marshal.ThrowExceptionForHR(ComHelperClass.E_NOINTERFACE);
            return 0; // S_OK
        }
        public int LockServer(bool fLock)
        {
            return 0; // S_OK
        }
        #endregion
    }


3.编写代码启动com工厂,调用;并编译生成程序

  static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            RegisterDcomServer();
            Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
            Application.Run(new Form1());
        }


        static void Application_ApplicationExit(object sender, EventArgs e)
        {
            RevokeDcomServer();
        }


        private static void RegisterDcomServer()
        {
            // 做一些安全检查,确保只有一些有权限的人才能调用你的C# Dcom组件
            // 如果你对安全性不关心的话,可以删除下面的语句
            //int hr = ComHelperClass.CoInitializeSecurity(
            //    IntPtr.Zero, // 这里要输入你的安全描述符
            //    -1,
            //    IntPtr.Zero,
            //    IntPtr.Zero,
            //    ComHelperClass.RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
            //    ComHelperClass.RPC_C_IMP_LEVEL_IDENTIFY,
            //    IntPtr.Zero,
            //    ComHelperClass.EOAC_DISABLE_AAA | ComHelperClass.EOAC_SECURE_REFS | ComHelperClass.EOAC_NO_CUSTOM_MARSHAL,
            //    IntPtr.Zero);
            //if (hr != 0)
            //    Marshal.ThrowExceptionForHR(hr);


            int hr = ComHelperClass.CoRegisterClassObject(
                ComHelperClass.CLSID_TestComVisibleClass,
                new ComClassFactory(),
                ComHelperClass.CLSCTX_LOCAL_SERVER,
                ComHelperClass.REGCLS_MULTIPLEUSE,
                out m_ComCookie);
            if (hr != 0)
                Marshal.ThrowExceptionForHR(hr);
        }


        private static void RevokeDcomServer()
        {
            if (m_ComCookie != 0)
                ComHelperClass.CoRevokeClassObject(m_ComCookie);

        }

     4.在本机注册com服务程序(管理身份运行 regasm)生成tlb文件,并修改添加注册表为本地服务(LocalServer32),删除自动生成的服务(inprocServer32)



查看系统注册表(建议使用RegWorkshop查看,检索guid )



vs使用的话到此就可以了,但如果c++调用的话还要在注册表里声明下tlb的信息

扫描二维码关注公众号,回复: 4692775 查看本文章

tlb信息可以用oleview进行查看,并在注册表添加信息



二、外部对com服务进行调用

    新建一个winform程序 ,编写调用代码,即可

        

  System.Type t = Type.GetTypeFromProgID("TestComServer.TestComVisibleClass");
            dynamic o = Activator.CreateInstance(t);

            o.TestMethod();

 至此我们的进程外com服务的编写和测试程序全部完成

完成的程序Demo 

注意下载Demo后,要现在本地进行com注册和相应注册表修改,如果感觉注册表操作麻烦,可以自己写个脚本

参考资料:

http://blog.csdn.net/zxdu721/article/details/7785277

https://www.cnblogs.com/killmyday/articles/1395432.html

https://www.codeproject.com/KB/COM/simplecomserver.aspx?display=Print

猜你喜欢

转载自blog.csdn.net/shu19880720/article/details/79537277