允许同一个COM库的多个版本

时间:2014-03-17 17:04:42

标签: c# com interop tlbimp

我编写了一个C#程序和库,允许用户更轻松地使用特定的专有模拟器的COM接口。

目前,我必须为我希望支持的每个版本的模拟器构建和分发不同版本的C#库。开发模拟器的公司定期发布新版本,每个新版本都会获得增加的主要版本号。据我所知,版本之间的COM接口没有变化(尚未),所以从我的角度看,调用和行为都是一样的。但是,如果我针对模拟器版本9.0构建我的库和安装程序,并且用户安装了版本10.0,则我的C#程序找不到模拟器的COM接口。 (即使对模拟器进行微小的升级也会导致COM接口的主要版本崩溃。)所以我必须针对每个支持的模拟器版本构建我的库。这很烦人,我宁愿分发一个在安装时正确查找并链接到最新模拟器的库。

似乎必须有办法做到这一点。我认为这个页面可能会描述方法:How to: Wrap Multiple Versions of Type Libraries。但它似乎并不适合我。

当然,我可能没有正确地做到这一点。我按照指示获取两个版本的COM接口的.il文件。 9.0和10.0。但我对下一步感到困惑,无法找到一个例子:

  

使用文本编辑器,在Tlbimp.exe添加的属性下插入第二个PrimaryInteropAssemblyAttribute属性。包括代表第二种类型库版本的主要版本号和次要版本号。

我不确定是否应该复制程序集块,或者只是块内的行(没有我能看到的版本信息。)所以我像这样复制了程序集块:

enter code here
.assembly Interop.Happ
{
  .custom instance void 
    [mscorlib]System.Runtime.InteropServices.ImportedFromTypeLibAttribute::.ctor(string) = ( 01 00 04 48 61 70 70 00 00 )
  .custom instance void 
    [mscorlib]System.Runtime.InteropServices.PrimaryInteropAssemblyAttribute::.ctor(int32, int32) = ( 01 00 09 00 00 00 00 00 00 00 00 00 ) 

   ////////////// [SNIP] ///////////////
  .ver 9:0:0:0
}
.assembly Interop.Happ
{
  .custom instance void
    [mscorlib]System.Runtime.InteropServices.ImportedFromTypeLibAttribute::.ctor(string) = ( 01 00 04 48 61 70 70 00 00 )
  .custom instance void 
    [mscorlib]System.Runtime.InteropServices.PrimaryInteropAssemblyAttribute::.ctor(int32, int32) = ( 01 00 0A 00 00 00 00 00 00 00 00 00 ) 

  ////////////// [SNIP] //////////////
  .ver 10:0:0:0
}
.module Interop.Happ.dll

这没有用,但我看不出我的其他解释是如何可行的。谁能看到我做错了什么?我是完全错误的轨道,还是我只是组合了.il文件的错误部分?

1 个答案:

答案 0 :(得分:0)

我们通过不使用tlbimp.exe并提供自定义包装器来解决我们产品的这个问题。

我们的包装器仅为接口提供.NET定义,忽略类型库和组件类。用户必须使用Activator API从ProgID获取实例,这当然可以成为其应用程序的配置参数。

这是可管理的,因为接口是不可变的,因此我们必须为每个接口创建一个包装类,即使实现发展也是如此。

示例包装器:

[ComImport, Guid("PUT-GUID-HERE")]
public interface IProdistLogger
{
    [DispId(1000)]
    string Name { [return: MarshalAs(UnmanagedType.BStr)] get; }

    [DispId(1001)]
    void LogSimple (long level, [MarshalAs(UnmanagedType.BStr)] string message, object location);
}

[ComImport, Guid("PUT-GUID-HERE")]
public interface IProdistLoggingHierarchy
{
    [DispId(1000)]
    string Type { [return: MarshalAs(UnmanagedType.BStr)] get; }

    [DispId(1001)]
    IProdistLogger CreateLogger ([MarshalAs(UnmanagedType.BStr)] string name);
}

[ComImport, Guid("PUT-GUID-HERE")]
public interface IProdistLogging
{
    [DispId(1000)]
    IProdistLoggingHierarchy CreateHierarchy ([MarshalAs(UnmanagedType.BStr)] string type, object configuration);
}

客户端示例:

public class Program
{
    public static void Main (string[] args)
    {
        IProdistLogging logging = (IProdistLogging)System.Activator.CreateInstance(Type.GetTypeFromProgID("prodist.logging.Logging.5.4"));
        IProdistLoggingHierarchy hierarchy = logging.CreateHierarchy("log4cxx", null);
        return;
    }
}