代码改变世界

.NET与COM互操作(1)-绑定与com对象创建

2010-08-26 23:53  Clingingboy  阅读(1530)  评论(0编辑  收藏  举报

早期绑定

即定义了强类型

分两种方式
1.使用工具自动生成
   1.1添加引用,则自动声明命名空间
   1.2运行TlbImp命令来声明,可修改命名空间

2.手动编写,可以使用
  可调用部分com接口,无需全部声明,但非常麻烦

以下为示例

1.自动声明的代码

可用实例或接口

static void CreateInstanceByWrapper()
 {
     int num0 = 6, num1 = 4;
 
     SimpleCOMCalculatorClass calcObj = new SimpleCOMCalculatorClass();
 
     Console.WriteLine("运?算?:?{0} + {1} = {2}",
         num0, num1, calcObj.Add(num0, num1));
 
     Console.WriteLine("运?算?:?{0} - {1} = {2}",
         num0, num1, calcObj.Subtract(num0, num1));
 
     ISimpleCOMCalculator calcInterfaceObj = new SimpleCOMCalculatorClass();
 
     Console.WriteLine("运?算?:?{0} * {1} = {2}",
         num0, num1, calcInterfaceObj.Multiply(num0, num1));
 
     Console.WriteLine("运?算?:?{0} / {1} = {2}",
         num0, num1, calcInterfaceObj.Divide(num0, num1));
 
     int factorialResult = num1;
     calcInterfaceObj.Factorial(ref factorialResult);
     Console.WriteLine("运?算?:?!{0} = {1}",
                     num1, factorialResult);
 
 }

2.自己手动创建代码

虽然灵活,但容易出错,很麻烦,不推荐

[ComImport]
   [Guid("C7386CE7-47B0-43C4-82D4-5FFA7A359EEA")]
   public class SimpleCOMCalculatorWrapper
   {
   }
 
   [ComImport]
   [CoClass(typeof(SimpleCOMCalculatorWrapper))]
   [Guid("FB1DE569-9B3D-491F-8EFC-25478CFBF172")]
   public interface ISimpleCOMCalculatorWrapper
   {
       [DispId(1)]
       int Add(int num0, int num1);
   }
 
   public class CreateInstanceByCustomeWrapperClass
   {
       public static void DoTest()
       {
           SimpleCOMCalculatorWrapper obj = new SimpleCOMCalculatorWrapper();
           ISimpleCOMCalculatorWrapper intf = obj as ISimpleCOMCalculatorWrapper;
           if (null != intf)
           {
               int result = intf.Add(1, 2);
               Console.WriteLine("\n用?自?定?义?包?装?类?创?建?COM对?象?。?计?算?器?:?+ 2 = {1}",
                   obj.GetType().Name, result);
           }
       }
   }


后期绑定



这个很好用,采用了反射技术,无需定义任何东西就可以调用com,由于是动态的,所以性能不比前期绑定的好.

用Type的GetTypeFromProgID或GetTypeFromCLSID方法获取都可以

static void Main(string[] Args)
 {
     // 通?过?ProgID返?回?COM对?象?类?型?
     Type comType = Type.GetTypeFromProgID(
         "SampleCOMSimple.SimpleCOMCalculator.1");
 
     // 也?可?以?通?过?CLSID返?回?COM对?象?类?型?
     //Guid clsid = new Guid("C7386CE7-47B0-43C4-82D4-5FFA7A359EEA");
     //Type comType = Type.GetTypeFromCLSID(clsid);
 
     // 创?建?COM对?象?实?例?
     Object comObj = Activator.CreateInstance(comType);
 
     // 设?置?方?法?参?数?
     Object[] methodArgs = { 6, 4 };
 
     // 调?用?加?法?
     Object result = comType.InvokeMember(
         "Add", BindingFlags.InvokeMethod, null,
         comObj, methodArgs);
 
     Console.WriteLine("运?算?:?{0} + {1} = {2}",
         methodArgs[0], methodArgs[1], result);
 
     // 调?用?减?法?
     result = comType.InvokeMember(
         "Subtract", BindingFlags.InvokeMethod, null,
         comObj, methodArgs);
 
     Console.WriteLine("运?算?:?{0} - {1} = {2}",
         methodArgs[0], methodArgs[1], result);
 
     // 调?用?乘?法?
     result = comType.InvokeMember(
         "Multiply", BindingFlags.InvokeMethod, null,
         comObj, methodArgs);
 
     Console.WriteLine("运?算?:?{0} * {1} = {2}",
         methodArgs[0], methodArgs[1], result);
 
     // 调?用?除?法?
     result = comType.InvokeMember(
         "Divide", BindingFlags.InvokeMethod, null,
         comObj, methodArgs);
 
     Console.WriteLine("运?算?:?{0} / {1} = {2}",
         methodArgs[0], methodArgs[1], result);
 
     // 调?用?阶?乘?方?法?
     // 由?于?参?数?需?要?从?方?法?中?返?回?结?果?,?要?使?用?ParameterModifier
     ParameterModifier paramMod = new ParameterModifier(1);
     paramMod[0] = true;
 
     int factorialArg = 4;
     Object[] methodArgs1 = { factorialArg };
     result = comType.InvokeMember(
         "Factorial", BindingFlags.InvokeMethod, null,
         comObj, methodArgs1, new ParameterModifier[] { paramMod },
         null, null);
     Console.WriteLine("运?算?:?!{0} = {1}",
                     factorialArg, methodArgs1[0]);
 
     Console.WriteLine("\r\n按?任?意?键?退?出?...");
     Console.Read();    
 }

p/invoke创建com对象

CoCreateInstance方法可以创建com对象,所以可以声明在托管代码中

//STDAPI CoCreateInstance(
 //  REFCLSID rclsid,
 //  LPUNKNOWN pUnkOuter,
 //  DWORD dwClsContext,
 //  REFIID riid,
 //  LPVOID * ppv
 //);
 [DllImport("ole32.dll", ExactSpelling = true)]
 private static extern int CoCreateInstance(
     [In] ref Guid clsid,
     IntPtr pUnkOuter,
     uint context,
     [In] ref Guid iid,
     [Out] out IntPtr ppv);
 
 //HRESULT CLSIDFromProgID(
 //  LPCOLESTR lpszProgID,
 //  LPCLSID pclsid
 //);
 [DllImport("ole32.dll", ExactSpelling = true)]
 private static extern int CLSIDFromProgID(
     [MarshalAs(UnmanagedType.LPWStr)] string progid,
     ref Guid clsid);

得到指针以后然后再将其转换为托管的com接口

public static void DoTest()
        {
            Guid clsid = new Guid();
            int hr = CLSIDFromProgID("SampleCOMSimple.SimpleCOMCalculator.1", ref clsid);
            if (0 == hr) // S_OK
            {
                Guid idispatch_id = new Guid("00020400-0000-0000-C000-000000000046");
                IntPtr pIDispatch;
                hr = CoCreateInstance(
                    ref clsid,
                    IntPtr.Zero,
                    1, // CLSCTX_INPROC_SERVER
                    ref idispatch_id,
                    out pIDispatch);
 
                if (0 == hr)
                {
                    object obj = Marshal.GetObjectForIUnknown(pIDispatch);
                    if (null != obj)
                    {
                        ISimpleCOMCalculator intf = obj as ISimpleCOMCalculator;
                        int result = intf.Add(1, 2);
                        Console.WriteLine("用?PInvoke创?建?COM对?象?。?计?算?器?:?+ 2 = {1}",
                            obj.GetType().Name, result);
                    }
                }
            }
        }