个人认为DELPHI实现activex控件的限制存在于DELPHI的activex控件的基类派生于TAutoObject如下: TActiveXControl = class(TAutoObject, IConnectionPointContainer, IDataObject, IObjectSafety, IOleControl, IOleInPlaceActiveObject, IOleInPlaceObject, IOleObject, IPerPropertyBrowsing, IPersistPropertyBag, IPersistStorage, IPersistStreamInit, IQuickActivate, ISimpleFrameSite, ISpecifyPropertyPages, IViewObject, IViewObject2) .... .... end; 用DELPHI制作过activex控件的人都知道DELPHI的activex控件向导中必须指明控件包含的VCL窗体控件(从TWinControl派生的VCL控件),这样就使得它的实现必须包含一个VCL窗体控件,而为了让这个VCL窗体控件随时可用DELPHI还要为该控件提供一个父窗口。看下面代码: procedure TActiveXControl.Initialize; begin inherited Initialize; FConnectionPoints := TConnectionPoints.Create(Self); FControlFactory := Factory as TActiveXControlFactory; if FControlFactory.EventTypeInfo <> nil then FConnectionPoints.CreateConnectionPoint(FControlFactory.EventIID, ckSingle, EventConnect); FPropertySinks := FConnectionPoints.CreateConnectionPoint(IPropertyNotifySink, ckMulti, nil); FControl := FControlFactory.WinControlClass.CreateParented(ParkingWindow); if csReflector in FControl.ControlStyle then FWinControl := TReflectorWindow.Create(ParkingWindow, FControl) else FWinControl := FControl; FControlWndProc := FControl.WindowProc; FControl.WindowProc := WndProc; InitializeControl; end; 这就是DELPHI实现activex控件的限制,我们如何去控制这个ParkingWindow,就算能够控制整个activex控件的体积以及膨胀了很多了,在internet上的activex控件越小越好,至少现在的DELPHI要实现类似vc轻量级控件(只实现IPersistStreamInit,IOleControl,IOleObject,IOleInPlaceActiveObject,IViewObjectEx,IOleInPlaceObjectWindowless这些接口的COM对象)非常困难,更不要说要按需(根据activex控件的使用范围是IE还是word或者其他)实现接口了。一种解决方案就是不从TAutoObject派生而是直接从窗体控件派生如下: TMyActiveXControl=class(TMyControl, //TMyControl是一般的类也可以是VCL窗体控件类. //下面的接口并不总是需要派生和实现。可按需派生和实现 IConnectionPointContainer, IDataObject, IObjectSafety, IOleControl, IOleInPlaceActiveObject, IOleInPlaceObject, IOleObject, IPerPropertyBrowsing, IPersistPropertyBag, IPersistStorage, IPersistStreamInit, IQuickActivate, ISimpleFrameSite, ISpecifyPropertyPages, IViewObject, IViewObject2) .... .... end; 但是如果这样,新的问题又产生了,如何注册这个activex控件呢?因为没有合适的类厂对象,DELPHI的类厂是如下关系: TComObjectFactory-->TTypedComObjectFactory-->TAutoObjectFactory -->TActiveXControlFactory-->TActiveFormFactory 而TComObjectFactory是这样实现的, TComObject = class(TObject, IUnknown, ISupportErrorInfo) 。。。。 End; TComClass = class of TComObject; TComObjectFactory = class(TObject, IUnknown, IClassFactory, IClassFactory2) ….. constructor Create(ComServer: TComServerObject; ComClass: TComClass; const ClassID: TGUID; const ClassName, Description: string; Instancing: TClassInstancing; ThreadingModel: TThreadingModel = tmSingle); End; 类厂的构造函数要求ComClass这个参数,而TComObject是从TObject派生的,因此如我们根本找不到合适的类厂基类来派生,除非有下面的delphi实现: TMyComObject = class(TMyControl, IUnknown, ISupportErrorInfo) 。。。。 End; TMyComClass = class of TMyComObject; TMyComObjectFactory = class(TObject, IUnknown, IClassFactory, IClassFactory2) ….. constructor Create(ComServer: TComServerObject; MyComClass: TMyComClass; const ClassID: TGUID; const ClassName, Description: string; Instancing: TClassInstancing; ThreadingModel: TThreadingModel = tmSingle); End; 可惜就算有这样的一个类我们也无法使用,这个限制来自于DELPHI对COM类厂的实现如下: TComServer = class(TComServerObject) Private 。。。。 procedure FactoryFree(Factory: TComObjectFactory); procedure FactoryRegisterClassObject(Factory: TComObjectFactory); procedure FactoryUpdateRegistry(Factory: TComObjectFactory); procedure LastReleased; end; 问题就出在这几个函数,这几个函数要求参数是TComObjectFactory类型,也就是说要使用delphi提供的COM服务器的实现,那么COM对象的类厂就必须从TComObjectFactory派生,我没想通这儿为什么不使用接口,比如是如下实现: TComServer = class(TComServerObject) Private 。。。。 procedure FactoryFree(Factory: IClassFactory); procedure FactoryRegisterClassObject(Factory: IClassFactory); procedure FactoryUpdateRegistry(Factory: IClassFactory); procedure LastReleased; end; 追根到底问题出在delphi提供的COM服务器的实现以及类厂的实现上了,这下就没法了,至少我现在还没有找到什么好办法,现在想到的就只有自己实现COM服务器dll以及自己的activex控件类工厂了(实际上也做了一个,感觉还是很简单,有些delph实现COM服务器的的方法可以直接使用)。 |