【问题标题】:Com interop: Why tlibimp.exe generates read only properties?Com interop:为什么 tlibimp.exe 生成只读属性?
【发布时间】:2012-08-15 15:10:28
【问题描述】:

我用 Visual Studio 创建了一个 COM 对象,我想在 Delphi 中使用它。

[Guid("9D0CCD2D-75E9-46AC-BC40-C4D84669FC45")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMyComClassDispatch
{
    string PropertyString { get; set; }
    string funcGetString();
    void funcSetString(string aString);
}

[ClassInterface(ClassInterfaceType.None)]
public class MyComClassDispatch : IMyComClassDispatch
{
    public string PropertyString { get; set; }


    public string varString;

    public string funcGetString()
    {
        return varString;
    }

    public void funcSetString(string aString)
    {
        varString = aString;
    }
}

然后我生成了 tlb 文件,最后生成了一个与我的 COM 对象对应的 pascal 文件,其中 tlibimp.exe 与 Delphi 5 捆绑在一起:

C:\>tlibimp.exe -P+ mylib.tlb

这是生成的代码:

// *********************************************************************//
// DispIntf:  IMyComClassDispatch
// Flags:     (4096) Dispatchable
// GUID:      {9D0CCD2D-75E9-46AC-BC40-C4D84669FC45}
// *********************************************************************//
  IMyComClassDispatch = dispinterface
    ['{9D0CCD2D-75E9-46AC-BC40-C4D84669FC45}']
    property PropertyString: WideString readonly dispid 1610743808;
    function  funcGetString: WideString; dispid 1610743810;
    procedure funcSetString(const aString: WideString); dispid 1610743811;
  end;

问题是我的属性被标记为只读,我真的不明白为什么会这样,因为这个工具也可以生成 C++ 代码并且可以修改属性:

// *********************************************************************//
// Interface   : IMyComClassDispatch
// Indicateurs : (4096) Dispatchable
// GUID        : {9D0CCD2D-75E9-46AC-BC40-C4D84669FC45}
// *********************************************************************//
interface IMyComClassDispatch : public TDispWrapper<IDispatch>
{
  BSTR __fastcall get_PropertyString()
  {
    _TDispID _dispid(/* PropertyString */ DISPID(DISPID_UNKNOWN/*[1610743808]*/));
    TAutoArgs<0> _args;
    OlePropertyGet(_dispid, _args);
    return _args.GetRetVariant();
  }

  void __fastcall set_PropertyString(BSTR Param1/*[in]*/)
  {
    _TDispID _dispid(/* PropertyString */ DISPID(1610743808));
    TAutoArgs<1> _args;
    _args[1] = Param1 /*[VT_BSTR:0]*/;
    OlePropertyPut(_dispid, _args);
  }

  BSTR __fastcall funcGetString()
  {
    _TDispID _dispid(/* funcGetString */ DISPID(DISPID_UNKNOWN/*[1610743810]*/));
    TAutoArgs<0> _args;
    OleFunction(_dispid, _args);
    return _args.GetRetVariant();
  }

  void __fastcall funcSetString(BSTR aString/*[in]*/)
  {
    _TDispID _dispid(/* funcSetString */ DISPID(DISPID_UNKNOWN/*[1610743811]*/));
    TAutoArgs<1> _args;
    _args[1] = aString /*[VT_BSTR:0]*/;
    OleProcedure(_dispid, _args);
  }


  __property   BSTR            PropertyString = {read = get_PropertyString, write = set_PropertyString};
};

这是否意味着我应该避免使用 COM 对象的属性,或者我应该更改任何选项?这是 tlibimp 的问题还是编译器的限制,无法生成在 COM 对象属性上写入的指令?

对此的任何帮助将不胜感激!

【问题讨论】:

  • 也许the right time 用于升级?
  • 其实我希望我可以使用COM Interop顺利升级到.NET...

标签: c++ delphi com


【解决方案1】:

这是 Delphi 5 和 6 tlibimp.exe 中的已知缺陷。您应该升级到 Delphi 7 或更新版本以避免它。

【讨论】:

  • 你有什么来源可以证明你在说什么吗?我几乎可以肯定它来自这个旧版本,但没有提供任何解决方法......
  • @EliasPlatek 我几年前遇到过同样的问题。除了手动(或通过某些脚本)编辑生成的文件外,没有找到任何解决方法,这当然不是工业过程可接受的解决方案。参见例如在这里讨论:managed-vcl.com/phpBB3_2/viewtopic.php?f=2&t=9
  • 感谢您的链接!实际上我只需要更新版本的 tlibimp.exe 对吗?还是每个版本都有问题?
  • @EliasPlatek 您可以尝试使用 Delphi 7 中的 tlibimp,但我担心 tlibimp 的较新版本会生成无法在旧版本的 Delphi 下编译的代码。我记得我们为此检查了几个解决方法,但最终转移到了 Delphi 7。
【解决方案2】:

Tlibimp.exe 在 Delphi 5 中存在漏洞,Borland/CodeGear/Embarcadero 不再提供支持...

解决方法是删除生成的 pas 文件上的只读标记。但是为了确保代码被正确调用,我做了一些修改来证明它可以工作:

  • 在COM对象类中,在setter中写入一个文件:

    public string PropertyString
    {
        get { return varString; }
        set
        {
            varString = value;
            File.WriteAllText(@"C:\Users\elias\Documents\com.txt", varString);
        }
    }
    
  • 删除从 tlibimp.exe 生成的 .pas 文件中属性上的只读标记:

    // *********************************************************************//
    // DispIntf:  IMyComClassDispatch
    // Flags:     (4096) Dispatchable
    // GUID:      {9D0CCD2D-75E9-46AC-BC40-C4D84669FC45}
    // *********************************************************************//
      IMyComClassDispatch = dispinterface
        ['{9D0CCD2D-75E9-46AC-BC40-C4D84669FC45}']
        property PropertyString: WideString dispid 1610743808;
        function  funcGetString: WideString; dispid 1610743810;
        procedure funcSetString(const chaine: WideString); dispid 1610743811;
      end;
    
  • 然后你就可以使用你的 COM 对象了:

    var
      MyClass: IMyComClassDispatch;
    begin
      try
        MyClass:= CoMyComClassDispatch.Create;
        MyClass.PropertyString:= 'some value';
      finally
        MyClass._Release;
      end;
    end;
    

并且文件被正确写入!

现在是我项目中唯一遇到的问题,希望以后不会再有其他问题了……

【讨论】:

    猜你喜欢
    • 2011-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多