F# 和 C# 中 COM 对象创建的区别
Difference in COM object creation in F# and C#
有两个相同的 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# 版本失败
An unhandled exception of type System.MissingMethodException
occurred in mscorlib.dll
Additional information: Attempted to access a missing member.
当我尝试如下调用成员时(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
工作正常
好吧,这将是 F# 如何实现接口的问题。这些接口的实现方式是只能通过接口本身调用它们,而不是通过 class.
以下代码有效:
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。
有两个相同的 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# 版本失败
An unhandled exception of type
System.MissingMethodException
occurred in mscorlib.dll
Additional information: Attempted to access a missing member.
当我尝试如下调用成员时(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
工作正常
好吧,这将是 F# 如何实现接口的问题。这些接口的实现方式是只能通过接口本身调用它们,而不是通过 class.
以下代码有效:
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。