F#和C#中COM对象创建的差异

时间:2015-01-23 00:30:39

标签: c# com f# c#-to-f#

有两个相同的COM对象定义。

F#版本,WebUIPlugin项目:

namespace WebUIPlugin

open System
open System.Runtime.InteropServices

[<Guid("BAEF0C5B-EFA5-4868-8342-7A1E6F8F7AF4")>]
type IPlugin =
    [<DispId(1)>]
    abstract OpenFormFromFile : path:string -> unit

[<Guid("8D71E2DB-D718-4595-B856-58D14EEAEBB2");
ClassInterface(ClassInterfaceType.None);
ComVisible(true)>]
type Plugin() = class
  interface IPlugin with
    member this.OpenFormFromFile(path) = ()
  end
end

C#版本,WebUIPlugin2项目:

using System;
using System.Runtime.InteropServices;

namespace WebUIPlugin
{
    [Guid("BAEF0C5B-EFA5-4868-8342-7A1E6F8F7AF4")]
    public interface IPlugin
    {
        [DispId(1)]
        void OpenFormFromFile(string path);
    }

    [Guid("8D71E2DB-D718-4595-B856-58D14EEAEBB2")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComVisible(true)]
    public class Plugin : IPlugin
    {
        public void OpenFormFromFile(string path)
        {
        }
    }
}

项目设置相同。

虽然C#定义运行良好,但F#版本失败并带有

  

mscorlib.dll中发生了System.MissingMethodException类型的未处理异常   其他信息:试图访问失踪成员。

当我尝试按如下方式调用成员时(Example2项目):

class Program
{
    static void Main(string[] args)
    {
          var objectType = Type.GetTypeFromProgID("WebUIPlugin.Plugin");
          dynamic handler = Activator.CreateInstance(objectType);
          objectType.InvokeMember("OpenFormFromFile", BindingFlags.InvokeMethod, null, handler, new object[]{""});
    }
}

汇编:

CALL "c:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\vcvars32.bat"

MSBuild.exe WebUIPlugin.sln /nologo /target:Build /p:Configuration=Debug /p:Platform="x64"

注册:

c:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe /codebase /verbose WebUIPlugin\bin\x64\Debug\WebUIPlugin.dll 

测试:

C:\...\> Example2\bin\x64\Debug\Example2.exe

Unhandled Exception: System.MissingMethodException: Method 'WebUIPlugin.Plugin.OpenFormFromFile' not found.
   at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
   at CallSite.Target(Closure, CallSite, Type, String, BindingFlags, Object, Object, Object[])
   at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid6[T0,T1,T2,T3,T4,T5](CallSite site, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
   at Example2.Program.Main(String[] args) in ...\Example2\Program.cs:line 16

注册C#版本:

c:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe /codebase /verbose WebUIPlugin2\bin\x64\Debug\WebUIPlugin2.dll 

测试:

C:\...\> Example2\bin\x64\Debug\Example2.exe

工作正常

1 个答案:

答案 0 :(得分:2)

嗯,它将成为F#如何实现接口的问题。接口的实现方式只能通过接口本身调用,而不能通过类调用。

以下代码有效:

var objectType = Type.GetTypeFromProgID("WebUIPlugin.Plugin");
var handler = Activator.CreateInstance(objectType);
var types = objectType.FindInterfaces((_1, _2) => true, null);
var iPlugin = types.First(t => t.Name == "IPlugin");
iPlugin.InvokeMember("OpenFormFromFile", BindingFlags.InvokeMethod, null, handler, new object[]{""});

为了使它工作,F​​#接口也应该是ComVisible。