1、有一个vcl控件TA,它有一个属性是,Items:TItemCollection,派生自TCollection;
2、我想把TA封装成一个com组件,供别的语言使用,希望能够这样使用:AxObject.Items.Count;
3、创建了一个IAx接口,实现的部分把相应功能转给A的一个实例,即:
  TAx=class(T**, IAx)
  private
    FA:TA;
  protected
    function Get_Items(out Value: IItems): HRESULT; safecall;
    function Set_Items(Value: IItems): HRESULT; safecall;
    ……
  end;
  实现为:
  function Get_Items(out Value: IItems): HResult;
  begin
    Value := FA.Items as IItems;
  end;
4、为了实现上述做法,再声明一个接口,IItems,然后让TItemCollection实现IItems;
5、问题出来了,IItems=interface(IDispatch),如果要TItemCollection实现IItems,则必须要实现IDispatch的一堆方法,例如Invoke、GetIDsByName等等;
6、看了一下VCL,TComponent默认实现了IDispatch的方法,所以派生自TComponent的类,再让它实现IDispatch丝毫不增加工作量;但上面TItemCollection派生自TCollection,则没有便利基于上面的尝试,我对这样封装的方式产生了极大的怀疑,希望高手们:
1、能帮我理清这种方式的思路;
2、提出更好的解决方案。多谢了。

解决方案 »

  1.   

    楼主看看这个合不合用?TCPCollection = class(TAutoObject, ICPCollection)
    private
       FCollection : TVariantCollection;
    protected
       function _NewEnum: IUnknown; safecall;
       function Add(Item, vntIndexKey: OleVariant): OleVariant; safecall;
       function Count: Integer; safecall;
       function Get_Item(Key: OleVariant): OleVariant; safecall;
       procedure Clear; safecall;
       procedure Remove(vntIndexKey: OleVariant); safecall;
       function ItemExists(Key: OleVariant): WordBool; safecall;
    public
       procedure Initialize; override;
    end;function TCPCollection._NewEnum: IUnknown;
    begin
       Result:= FCollection.GetEnum;
    end;function TCPCollection.Get_Item(Key: OleVariant): OleVariant;
    begin
       try
          Result:= FCollection.Items[Key];
          except
             Raise EOleException.Create('CPCollection Error - Invalid Item retrieving',1819,'','',0);
       end;
    end;procedure TCPCollection.Remove(vntIndexKey: OleVariant);
    begin
       try
          FCollection.Delete(vntIndexKey);
          except
             Raise EOleException.Create('CPCollection Error - Invalid Item remove',1818,'','',0);
       end;
    end; function TCPCollection.Add(Item, vntIndexKey: OleVariant): OleVariant;
    var
       lString: String;
       lKeyPresent: Boolean;
    begin
       lKeyPresent:= True;
       try
          lString:= VarToStr(vntIndexKey) + 'ss';
          except
             lKeyPresent:= False;
       end;
       try
          if lKeyPresent then
             if lKeyPresent then begin
                if ItemExists(vntIndexKey) then
                   Raise EOleException.Create('', 2, '', '', 0);
                FCollection.AddObject(vntIndexKey, Item)
             end else
                FCollection.Add(Item);
          Result:= Item;
          except
             Raise EOleException.Create('CPCollection Error - Invalid Item add',1820,'','',0);
       end;
    end;function TCPCollection.ItemExists(Key: OleVariant): WordBool;
    var
       lItem : OleVariant;
    begin
       Result:= True;
       try
          lItem:= Get_Item(Key);
          except
             Result:= False;
       end;
    end;
      

  2.   

    to 帕拉丁:这样的话,聚合这个Items的类都得改,原来是TVariantCollection,现在嘛,或者都改成接口ICPCollection,或者都改成TCPCollection,是不是这个意思?
    感觉这么做比较彻底,都转成com对象了;比较担心的一点是,这个vcl组件比较庞大,这么改改动可能比较大一些,多谢!