2

我需要让一段 C# 代码通过 COM 与各种实现进行交互。

为了使该集成的用户更容易,我在 IDL 中包含了交互接口(作为相关现有 DLL 的一部分,但没有 coclass 或实现),然后通过运行 Tlbimp 将其放入我的 C# 代码中以创建类型定义。

我实现了我的 C#,基于 Windows 注册表信息创建 COM 对象并将对象转换为我需要的接口。

然后我在一个单独的项目中创建了接口的 C# 实现并注册了它。主程序正确创建了测试 COM 对象,但未能将其转换为接口(使用 C#'as' 时获取空对象,获取显式转换的 InvalidCastException)。

有人可以建议为什么接口没有被测试对象识别为实现吗?

这是 IDL 中的接口定义(在 VS 2005 中用 C++ 编译):

    [
    object,
    uuid(B60C546F-EE91-48a2-A352-CFC36E613CB7),
    dual,
    nonextensible,
    helpstring("IScriptGenerator Interface"),
    pointer_default(unique)
]
interface IScriptGenerator : IDispatch{

    [helpstring("Init the Script generator")] 
        HRESULT Init();
    [helpstring("General purpose error reporting")] 
        HRESULT GetLastError([out] BSTR *Error);
};

这是 Tlbimp 为 C# 创建的存根:

[TypeLibType(4288)]
[Guid("B60C546F-EE91-48A2-A352-CFC36E613CB7")]
  public interface IScriptGenerator
  {
    [DispId(1610743813)]
    void GetLastError(out string Error);
    [DispId(1610743808)]
    void Init();
  }

这是主要 C# 代码的一部分,通过其 ProgID 创建一个 COM 对象并将其转换为 IScriptGenerator 接口:

public ScriptGenerator(string GUID)
{
  Type comType = Type.GetTypeFromProgID(GUID);
  object comObj = null;
  if (comType != null)
  {
    try
    {
      comObj = Activator.CreateInstance(comType);
    }
    catch (Exception ex)
    {
      Debug.Fail("Cannot create the script generator COM object due to the following exception: " + ex, ex.Message + "\n" + ex.StackTrace);
      throw ex;
    }
  }
  else
    throw new ArgumentException("The GUID does not match a registetred COM object", "GUID");

  m_internalGenerator = comObj as IScriptGenerator;
  if (m_internalGenerator == null)
  {
    Debug.Fail("The script generator doesn't support the required interface - IScriptGenerator");
    throw new InvalidCastException("The script generator with the GUID " + GUID + " doesn't support the required interface - IScriptGenerator");
  }

}

这是实现 C# 代码,以测试它是否正常工作(但它不是):

  [Guid("EB46E31F-0961-4179-8A56-3895DDF2884E"),
  ProgId("ScriptGeneratorExample.ScriptGenerator"),
  ClassInterface(ClassInterfaceType.None),
  ComSourceInterfaces(typeof(SOAAPIOLELib.IScriptGeneratorCallback))]
  public class ScriptGenerator : IScriptGenerator
  {
   public void GetLastError(out string Error)
    {
      throw new NotImplementedException();
    }
    public void Init()
    {
      // nothing to do
    }
  }
4

2 回答 2

2

再次 - 感谢您的建议。

我终于能够自己解决这个问题。我尝试了上述建议并没有取得任何进展。然后我在“测试”代码中更改了互操作的命名空间——它与主代码中的命名空间不同,因为使用 Tlbimp 时使用了不同的参数。这解决了问题。

这是我对原因的猜测:.Net 创建了 COM 对象,但是当它检测到这实际上是一个 .Net 对象时,它会绕过 COM 层并直接进行通信。在这种情况下,不使用 queryInterface(带有接口 GUID)并且接口确实因不同的 C# 命名空间而不同。

这意味着为了支持与 .Net 代码的集成,我需要在 IDL 旁边发布我的原始互操作程序集。

谢谢, 因巴尔

于 2008-11-11T23:52:51.700 回答
0

我认为您需要在界面上使用它

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
于 2008-11-11T22:14:12.977 回答