我需要在多个程序集中声明相同的接口 - 但不能引用公共库。
我对接口有相同的定义,但是当我尝试从另一个应用程序创建它的实例时出现此错误:
无法将类型为'myFilter'的对象强制转换为类型 'DirectShow.IBaseFilter'
(myFilter声明为:public class myfilter : DirectSow.IBaseFilter...
)
使用RegAsm.exe注册源对象
两个程序集都有声明:
[ComImport, System.Security.SuppressUnmanagedCodeSecurity,
Guid("56a86895-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IBaseFilter : IMediaFilter
...
代码被复制,因此IMediaFilter
和所有其他声明完全相同。
我尝试使用以下方法创建对象的实例:
Type type = Type.GetTypeFromCLSID(new Guid("A3927399-E3AE-41E2-B094-0EA815CC9B9C"));
IBaseFilter filter = (IBaseFilter)Activator.CreateInstance(type);
如何跨程序集转换对象?
答案 0 :(得分:2)
根据定义:你不能。两个独立的接口彼此无关,永远不会是"是一个"彼此之间的关系,即使他们有相同的"命名和相同的成员。
专业解决方案将独立程序集中的接口分开,然后根据需要引用此程序集作为许多其他程序集。所有其他被认为是黑客攻击(在C#/ .NET中)。
要在此特定情况下应用所述解决方案,您需要2个或3个程序集:
程序集#1 :("定义"接口)。这个"定义"是一个COM接口导入这种特殊情况:
[ComImport, System.Security.SuppressUnmanagedCodeSecurity,
Guid("56a86895-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IBaseFilter : IMediaFilter
大会#2: 引用程序集#1,并包含一个实现接口的类
装配#3: 引用程序集#1和#2,可以访问和使用/转换程序集#2中的类。不要(重新)在这里导入界面。这将是一个相同但完全"其他" .NET的接口,即使它具有相同的成员签名。
我认为大会#1和#2可以合并为一个。确保接口声明和类定义都是公共的。该键不是导入两次COM接口而是导入一次并引用它。
编辑:反映评论:
不要将COM接口和类与.NET接口混淆。 (顺便说一下,注释提到了一个类id而不是一个接口id,这在COM中是两个不同的东西。)
通过互操作层高度支持在.NET中访问COM类和接口。互操作层为您完成所有转换和编组,并通过方便的.NET界面访问COM组件。但是,此接口在(interop)组件中定义,并且这些组件(对于众所周知的,并且经常使用的COM组件)是分布式的,或者是原始COM组件的下载的一部分。从字面上看,它们位于所需的每台机器上。
另外一个概念上的区别,在COM中客户端(引用组件)通过引用服务器(引用组件)一个guid(这是类id),然后请求多态实现一个接口也只用 一个guid。因此,客户端可以通过仅知道两个guid并执行1-2 COM OS调用来使用组件的特定接口。在interop层中,这是黑盒子。在.NET中,客户端和服务器之间的绑定要强得多。
如果你想要定义这种类型的接口,那么你必须这样做:以某种方式定义 one 程序集中的接口然后将其分发给其他程序集中的每台机器正在使用界面并引用此界面。
如果您不接受最佳做法,请选择
你可以使用反射来实现类似的松散绑定,但在这种情况下,这被认为是黑客攻击并且似乎是不必要的。请准备好您的方法名称和类名称是字符串,或者至少不正确键入它们不会导致编译错误,但会导致运行时错误。
您也可以在.NET中定义和实现COM组件,但我不认为这是目标。 COM是一种传统(而且很酷)的技术,它在当时非常进步(并且不被理解/批评),但这已经超过了25年前(当它被引入时)
答案 1 :(得分:0)
(这是问题作者的解决方案DanW)
在DLL中:
汇编COM-Visible = checked
using System;
using System.Runtime.InteropServices;
namespace ComExport
{
[ComImport]
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[TypeIdentifier()]
public interface ComClass1Interface
{
string DoCall();
}
[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938")]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class ComClass1 : ComClass1Interface
{
public string DoCall()
{
return "internal function called";
}
public override string ToString()
{
return "comclass1.tostring";
}
}
}
然后在EXE
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ComExportTester
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += (o1, e) => Close();
Type t;
object o;
ComExport.ComClass1Interface i1;
string s = "";
try
{
t = Type.GetTypeFromCLSID(new Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938"));
s += "Type found \t: " + (t == null ? "no" : "yes") + "\n";
o = t == null ? null : Activator.CreateInstance(t);
s += "object created \t: " + (o == null ? "no" : o.ToString()) + "\n";
i1 = o as ComExport.ComClass1Interface;
s += "interface cast \t: " + (i1 == null ? "no" : "yes") + "\n";
if (i1 != null)
s += i1.DoCall() + "\n";
}
catch (Exception x)
{
s += x.Message + "\n";
}
MessageBox.Show(s);
}
}
}
namespace ComExport
{
[ComImport]
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[TypeIdentifier()]
public interface ComClass1Interface
{
string DoCall();
}
}
两者:
设置x86或x64(在“任何CPU”模式下编译和运行会抛出“未注册”的异常!)