2

我编写了一个 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 文件的错误部分?

4

1 回答 1

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;
    }
}
于 2015-07-06T17:53:42.853 回答