【发布时间】:2014-10-28 00:16:42
【问题描述】:
我有一个 ATL COM 库,它在 MIDL 中定义了一个枚举和一个接口,例如:
[uuid(65785D49-574A-4B1B-95F1-B9C7F283364A)]
typedef enum Options
{
Option1,
Option2
} Options;
[
object,
uuid(2E3D1B1A-DF95-434F-836B-73FF1245B608),
oleautomation,
nonextensible,
pointer_default(unique)
]
interface IExample : IUnknown
{
HRESULT Test([in] Options option, [out, retval] BSTR* str);
};
然后我创建一个托管程序集并引用 TLB,TLB 创建一个 PIA 并将类型 (Embed Interop Types = true) 嵌入到托管程序集中。
在托管程序集中,我现在创建一个实现接口的类:
public class Example : IExample
{
public string Test(Options option)
{
return option.ToString();
}
}
现在我想创建第三个程序集,它引用托管程序集并创建对象并调用它,但它不允许我因为 Options 是未引用的类型(要求我包含从 typelib 生成的 PIA ):
public class Equivalence
{
public void UseTest()
{
Example e = new Example();
e.Test(Options.Option1); // recognizes that it requires an ExampleLib.Options parameter, but that type isn't available
}
}
使用反射器,我可以在托管程序集中看到它,但对象浏览器看不到它:
namespace ExampleLib
{
[ComImport, CompilerGenerated, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("2E3D1B1A-DF95-434F-836B-73FF1245B608"), TypeIdentifier]
public interface IExample
[Guid("65785D49-574A-4B1B-95F1-B9C7F283364A"), CompilerGenerated, TypeIdentifier("15a6cf97-c415-4866-bdfb-7da65edb1faa", "ExampleLib.Options")]
public enum Options
}
我的托管程序集本身就是一个旨在作为 API 分发的库,我想公开此枚举和接口,以便外部各方可以使用它,而不必交付从 ATL 的类型库生成的 PIA COM 库。有可能吗?
【问题讨论】:
-
不要嵌入类型!因为您想将 ATL 库与您的 API 一起分发,所以无论如何这不是您想要的。只有在引用 TLB 的程序集中使用的类型是嵌入的,因此客户端可能会丢失某些对象。相反,您应该从 TLB 创建一个 PIA,将其部署到 GAC 并在您想要使用它的类型的每个程序集中引用它。
-
我们根本不需要(或不希望)外部客户使用 ATL 库,他们唯一的访问权限应该是通过我们的托管 API。因此,我们需要通过此 API 公开的唯一类型是嵌入的类型。我慢慢得出结论,我需要分发 PIA 才能使其工作,但我希望它可以嵌入到程序集中以减少依赖关系。
-
唯一可以嵌入到程序集中的是互操作类型,它不同于底层的 COM 类型! ATL 库必须部署并注册到客户端,即使您嵌入互操作类型(它们只是 COM 库的包装器)。因此,客户端能够直接访问您的非托管类型库。控制这种情况的唯一方法是生成和分发 PIA。依赖关系在这里没有争议 - 它们是您的解决方案性质的结果。您不能通过省略某些组件来减少它们。
标签: c#-4.0 interop com-interop pia type-equivalence