0% found this document useful (0 votes)
18 views15 pages

Activex Delphi Invisible Component Library

Delphi support developing ActiveX libraries using TActiveXControl class that defines the core behavior and interfaces required of an ActiveX control.

Uploaded by

carlos_sa
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views15 pages

Activex Delphi Invisible Component Library

Delphi support developing ActiveX libraries using TActiveXControl class that defines the core behavior and interfaces required of an ActiveX control.

Uploaded by

carlos_sa
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

HOW TO DEVELOP ACTIVEX INVISIBLE COMPONENT LIBRARY IN DELPHI

Editor: Tom Mandys, [Link]@[Link] (2p plus) Home site: [Link] Document status: Version 1.0

First release

How to develop ActiveX invisible component library

Table of Contents 1. 2. Introduction ...........................................................................................................................3 Invisible component ..............................................................................................................3 2.1. [Link]...................................................................................................................3 2.2. Custom component........................................................................................................3 3. Example ................................................................................................................................3 3.1. Developing component ..................................................................................................3 3.2. Using new component in Excel ......................................................................................8 3.3. Using new component in Delphi.....................................................................................9 4. Links......................................................................................................................................9 5. Appendix .............................................................................................................................10 5.1. [Link].................................................................................................................10 5.2. [Link].................................................................................13

Disclaimer The information of this document is provided AS IS, with no warranties whatsoever, excluding in particular any warranty of merchantability, fitness for any particular purpose, or any warranty otherwise arising out of any proposal, specification, or sample. This document is provided for information purposes only.

-2-

How to develop ActiveX invisible component library

1. Introduction
Delphi support developing ActiveX libraries using TActiveXControl class that defines the core behavior and interfaces required of an ActiveX control and connects that behavior to any VCL control derived from TWinControl. This allows the control to be embedded in any ActiveX container, including Internet Explorer, Visual Basic, PowerBuilder, Paradox, Borland C++, IntraBuilder and, of course, Delphi. ActiveX has typical OCX extension and must be registered using regsvr32. But custom class must be descendant of a TWinControl and it means that implemented component is a visible control in both design and run-time. But not all components should be visible in Delphi terminology controls - all the time. Do many examples of invisible components exist timers, communication components, database connectors, loggers, protocol implementation, etc. Lets demonstrate how to develop invisible ActiveX components.

2. Invisible component
The typical invisible component should be indicated on a design form as an icon or bitmap and totally hidden in run-time. We have developed [Link] unit that is equivalent of common [Link] unit.

2.1.

[Link]

The main class TActiveXComponent is descendant of TActiveXControl and overrides some behavior. First is defined special TActiveXComponentControl that server visual indication of a component in design time. In run-time is sleeping behind the scene. The key property of the ActiveXComponentControl is BitmapId that references a component icon that appears on the design form. TActiveXComponent has assigned one TActiveXComponentControl instance and controls it hides it if run-time mode is recognized and shows it if design time is recognized. Such behavior was not easy to implement since Microsoft IDE (Visual Basic, Visual Basic for Application, etc.) and Delphi IDE behaves partially differently when manipulation with ActiveX library and a thing that works perfectly in Delphi does not work in VB.

2.2.

Custom component

Custom component will be descendant of TActiveXComponent and will implement a custom interface. Interface is defined in Delphi using Type Library editor TLB.

3. Example
3.1. Developing component
Lets say that you want create TStringList reusable as ActiveX component in OCX library. 1. run Delphi IDE

-3-

How to develop ActiveX invisible component library 2. change language of type library to Pascal if you prefer it to IDL (Tools/Environment options/Type library/Language) 3. create new project ActiveX library (File/New/ActiveX/ActiveX library)

Save project for example as MyInvisibleComponentXLibrary 4. add new ActiveX control (File/New/ActiveX/ActiveX control)

select any VCL Class Name, you will change it directly in IDE later enter your new component name in New ActiveX Name enter your Implementation unit name if you want license your library via .LIC file check Make control licensed Include version information enable to insert Project/Options/Version info to library

-4-

How to develop ActiveX invisible component library

Delphi wizard prepares type library and skeleton of new class implementation.

5. Open type library visual editor and remove all obsolete methods, properties, enumerations introduces for TEdit class.

Add properties, methods and events that you need publish in ActiveX component. Note that for TString use IStrings and for string use WideString.

-5-

How to develop ActiveX invisible component library

6. Delete obsolete methods from skeleton MyInvisibleComponentXImpl, probably all methods except FEvents, DefinePropertyPages, EventSinkChanged, InitializeControl. 7. Add AxCmps and MyInvisibleComponent to interface clause. 8. Change TMyInvisibleComponentX ancestor from TActiveXControl to TActiveXComponent that implements all visible features, i.e. in design time appears as icon, in run-time is hidden.
TMyInvisibleComponentX = class(TActiveXComponent, IMyInvisibleComponentX)

9. Add FMyInvisibleComponent of TMyInvisibleComponent to private section of TMyInvisibleComponentX declaration. Declare all methods to implement IMyInvisibleComponentX interface and events for IMyInvisibleComponentXEvents. Note that for IStrings use GetOleStrings and SetOleStrings procedures. It seems that ActiveX library compiled using Delphi have problem if an exception is raised in library. I observed that it is better safe all code to try expect statement, return result code and make LastErrorStr property to publish reason of exception (see Delete function implementation). 10. Override [Link] to initialize properties. 11. Override [Link] to assign special purpose property editor (for IStrings type). 12. Change initialization section TActiveXControlFactory to TActiveXComponentFactory and remove TEdit parameter. 13. Edit project properties, advertise version, developer, copyright etc.

-6-

How to develop ActiveX invisible component library

14. Edit [Link] resource (using ImageEditor for example) containing bitmap identified by ID number or modify existing one. Add line [Link]:=ID to InitializeControl method where ID is bitmap identifier in resource, default value is 1. Size of bitmap 26x26 pixels is expected. Note that I have in my Delphi 5 Project/Resources menu item but similar item is missing in Delphi7 maybe its a hack. Using this command you can add bitmap directly in IDE. External resource file must linked to library using {$R file} directive.

15. If you need use ActiveX library also in Delphi IDE you should change also *_TLB.PAS. Add OleCmps to interface uses section and change ancestor of TMyInvisibleComponentX from TOleControl to TOleComponent its hack that hides obsolete methods of TControl class in property editor.

-7-

How to develop ActiveX invisible component library Warning: *_TLB.PAS is generated by IDE when saving type library so changes made manually are overwritten.
TMyInvisibleComponentX = class(TOleComponent)

16. Ensure that license key in .LIC file is the same as license string passed in initialization section of TMyInvisibleComponentXImpl to [Link]. If not the same then the component is unable successfully place on a form. 17. Register library using regsvr32 utility
Regsvr32 [Link]

3.2.
1. 2. 3. 4.

Using new component in Excel

Open Microsoft Excel Show Control tools toolbar (right click at any toolbar and check Control tools) Click Add control Select [Link]

5. Place MyInvisibleComponentX to sheet

-8-

How to develop ActiveX invisible component library

3.3.

Using new component in Delphi

Create new package [Link] containing MyInvisibleComponentXLibrary_TLB and component resource [Link] that contains 26x26 pixels bitmap named MYINVISIBLECOMPONENTX. Link resource using {$R '[Link]'} directive, compile and install.

Now should appear your component at ActiveX palette tab. Assure that [Link] is ancestor of class in TLB. If is not then change it manually and recompile package. If you plan use OleCmps in more packages create new package containing OleCmps and introduce name of this package to requires section.
requires OleCmps;

4. Links
[Link]
HOWTO: Build an Office 2000 COM Add-In in Visual Basic

[Link]
The most valuable info concerning invisible ActiveX library written in Delphi

-9-

How to develop ActiveX invisible component library

[Link]
Complete source code of demo application

5. Appendix
5.1. [Link]

unit AxCmps; interface uses SysUtils, Classes, Controls, ActiveX, AxCtrls, {$IFDEF REGISTRATION}AxCtrlsReg, {$ENDIF}Windows, ComServ, ComObj, Graphics; type TActiveXComponentControl = class; TActiveXComponent = class(TActiveXControl, IOleControl) private fUserMode: WordBool; protected procedure ModeChanged; virtual; procedure InitializeControl; override; procedure ActiveXLoaded; virtual; { IOleControl } function GetControlInfo(var ci: TControlInfo): HResult; stdcall; function OnMnemonic(msg: PMsg): HResult; stdcall; function OnAmbientPropertyChange(dispid: TDispID): HResult; stdcall; function FreezeEvents(bFreeze: BOOL): HResult; stdcall; public property UserMode: WordBool read fUserMode; procedure Initialize; override; end; TActiveXComponentControl = class(TCustomControl) private fBitmapId: Integer; procedure SetRunTime(const Value: Boolean); function GetRunTime: Boolean; protected procedure Paint; override; procedure DesignPaint; virtual; public property BitmapId: Integer read fBitmapId write fBitmapId; constructor Create(AOwner: TComponent); override; property RunTime: Boolean read GetRunTime write SetRunTime; end; TActiveXComponentFactory = class({$IFDEF REGISTRATION}TRegActiveXControlFactory{$ELSE}TActiveXControlFactory{$ENDIF}) public constructor Create(ComServer: TComServerObject; ActiveXControlClass: TActiveXControlClass; const ClassID: TGUID; ToolboxBitmapID: Integer; const LicStr: string; MiscStatus: Integer; ThreadingModel: TThreadingModel = tmSingle); end; implementation

- 10 -

How to develop ActiveX invisible component library

{ TActiveXComponent } procedure [Link]; begin fUserMode:= True; // VB does not call OnAmbientPropertyChange, so it must be runtime default option inherited; ModeChanged; end; procedure [Link]; begin inherited; { if (Control <> nil) and (Control is TActiveXComponentControl) then TActiveXComponentControl(Control).BitmapId:= ; // default is 1 //UpperCase([Link]); } end; procedure [Link]; begin if (Control <> nil) and (Control is TActiveXComponentControl) then begin TActiveXComponentControl(Control).RunTime := fUserMode; end; end; function [Link](var ci: TControlInfo): HResult; begin Result := inherited GetControlInfo(ci); end; function [Link](msg: PMsg): HResult; begin Result := inherited OnMnemonic(msg); end; function [Link]( dispid: TDispID): HResult; var AD: IAmbientDispatch; begin Result := inherited OnAmbientPropertyChange(dispid); if (dispid = DISPID_UNKNOWN) or (dispid = DISPID_AMBIENT_USERMODE) then // called only by Delphi if (ClientSite <> nil) and ([Link](IAmbientDispatch, AD) = S_OK) then begin fUserMode:= [Link]; ModeChanged; end; end; function [Link](bFreeze: BOOL): HResult; begin Result := inherited FreezeEvents(bFreeze); if not bFreeze then ActiveXLoaded; // for VB - according [Link] end;

- 11 -

How to develop ActiveX invisible component library


procedure [Link]; begin end; { TActiveXComponentControl } constructor [Link](AOwner: TComponent); begin inherited Create(AOwner); if AOwner is TWinControl then Parent := (AOwner as TWinControl); Width := 26; Height := 26; ControlStyle:= [csOpaque, csFixedWidth, csFixedHeight, csNoStdEvents {, csReplicatable, {csNoDesignVisible}]; [Link]:= Width; [Link]:= Width; [Link]:= Height; [Link]:= Height; Visible:= False; fBitmapId:= 1; end; procedure [Link]; begin inherited Paint; // if not RunTime then // visibility is controled by ActiveX, // if tested here - MS Visual *, Excel does not show icon in designed if project being reloaded (even placing works OK) DesignPaint; end; procedure [Link]; var PaintRect: TRect; Bmp: TBitmap; begin PaintRect := Rect(1, 1, Width, Height); Bmp:= [Link]; try [Link](hInstance, fBitmapId); [Link](PaintRect, Bmp); finally [Link]; end; { [Link] := psDot; [Link] := bsClear; [Link]( 0, 0, Width, Height); } end; procedure [Link](const Value: Boolean); begin Visible:= not Value; SetDesigning(not Value, True); Repaint; end; function [Link]: Boolean; begin Result:= not (csDesigning in ComponentState); end;

- 12 -

How to develop ActiveX invisible component library

{ TActiveXComponentFactory } constructor [Link](ComServer: TComServerObject; ActiveXControlClass: TActiveXControlClass; const ClassID: TGUID; ToolboxBitmapID: Integer; const LicStr: string; MiscStatus: Integer; ThreadingModel: TThreadingModel); begin inherited Create(ComServer, ActiveXControlClass, TActiveXComponentControl, ClassID, ToolboxBitmapID, LicStr, MiscStatus or OLEMISC_SIMPLEFRAME or OLEMISC_ACTSLIKELABEL or OLEMISC_INVISIBLEATRUNTIME, ThreadingModel); end; end.

5.2.

[Link]

unit MyInvisibleComponentXImpl; {.$WARN SYMBOL_PLATFORM OFF} interface uses Windows, ActiveX, Classes, StdCtrls, SysUtils, ComServ, StdVCL, AXCtrls, AxCmps, MyInvisibleComponentXLibrary_TLB; type TMyInvisibleComponentX = class(TActiveXComponent, IMyInvisibleComponentX) private { Private declarations } FMyInvisibleComponent: TStringList; FEvents: IMyInvisibleComponentXEvents; fLastErrorStr: string; procedure ChangeEvent(Sender: TObject); protected { Protected declarations } procedure DefinePropertyPages(DefinePropertyPage: TDefinePropertyPage); override; procedure EventSinkChanged(const EventSink: IUnknown); override; procedure InitializeControl; override; function Get_Params: IStrings; safecall; procedure Set_Params(const Value: IStrings); safecall; function GetParam(const Name: WideString): WideString; safecall; procedure SetParam(const Name, Value: WideString); safecall; function Get_LastErrorStr: WideString; safecall; function Delete(aIndex: Integer): WordBool; safecall; end; implementation uses ComObj; { TMyInvisibleComponentX } procedure [Link](Sender: TObject); begin if FEvents <> nil then

- 13 -

How to develop ActiveX invisible component library


begin try [Link](); except end; end; end; procedure [Link](DefinePropertyPage: TDefinePropertyPage); begin DefinePropertyPage( Class_DStringPropPage ); {TODO: Define property pages here. Property pages are defined by calling DefinePropertyPage with the class id of the page. For example, DefinePropertyPage(Class_MyInvisibleComponentXPage); } end; procedure [Link](const EventSink: IUnknown); begin FEvents := EventSink as IMyInvisibleComponentXEvents; end; function TMyInvisibleComponentX.Get_LastErrorStr: WideString; begin Result:= fLastErrorStr; end; function TMyInvisibleComponentX.Get_Params: IStrings; begin GetOleStrings(FMyInvisibleComponent, Result); end; function [Link]( const Name: WideString): WideString; begin Result:=[Link][Name]; end; procedure [Link]; begin inherited; FMyInvisibleComponent:= [Link]({if required an Owner use Control}); [Link] := ChangeEvent; end; procedure TMyInvisibleComponentX.Set_Params(const Value: IStrings); begin SetOLEStrings(FMyInvisibleComponent, Value); end; procedure [Link](const Name, Value: WideString); begin [Link][Name]:= Value; end; function [Link](aIndex: Integer): WordBool; begin try [Link](0); // raises exception if index out of item range Result:= True; except

- 14 -

How to develop ActiveX invisible component library


on E: Exception do begin Result:= False; fLastErrorStr:= [Link]; end; end; end; initialization [Link]( ComServer, TMyInvisibleComponentX, Class_MyInvisibleComponentX, 1, '{8B69C9B8-A742-4F5C-98BF-44F7C3D41A03}', 0, tmBoth); end.

5.3.

[Link]

(* OleCmps - ActiveX non-visual component development support in Delphi * Copyright (c) 2003 by Mandys Tomas-MandySoft *) { URL: [Link] } unit OleCmps; interface uses OleCtrls; type TOleComponent = class(TOleControl) // hide obsolete properties private fDummy: string; published property Height: string read fDummy; property Width: string read fDummy; property Hint: string read fDummy; property HelpContext: string read fDummy; property Cursor: string read fDummy; end; implementation end.

- 15 -

Common questions

Powered by AI

To create an invisible ActiveX component library in Delphi, you should: 1) Run the Delphi IDE and set the type library language to 'Pascal'. 2) Create a new ActiveX library project and save it. 3) Add a new ActiveX control, providing necessary details like VCL class and ActiveX name. 4) Modify the class implementation, removing obsolete methods and adding required properties. 5) Set the superclass to TActiveXComponent for invisible features. 6) Override specific methods for initialization and property management. 7) Edit resources to include a bitmap for design time visibility. 8) Change library settings in Delphi to hide standard properties, ensuring it compiles correctly. 9) Register the library using 'regsvr32' .

Design considerations for ensuring invisibility of ActiveX components at runtime include using a host control, TActiveXComponentControl, that manages when the component should render visible (design-time) or be hidden (runtime). Implementation relies on overriding the `ModeChanged` method to toggle visibility based on environment mode. Additionally, bitmap resources are used to offer design-time icons that do not affect runtime execution .

TMyInvisibleComponentX is tailored for Excel by implementing design-time visible elements like the TActiveXComponentControl bitmap, and at runtime, it remains hidden. It provides interfaces and methods tailored to Excel's environment, such as `GetParams` and `SetParams`, which facilitate communication with Excel's data structures. Proper event synchronization is also ensured to interact smoothly with Excel .

An invisible ActiveX component in Delphi faces challenges due to different behaviors across IDEs. For instance, the default handling of runtime and design-time modes can vary, resulting in components that work in Delphi but not in Visual Basic. Strategies such as customizing the `ModeChanged` method and handling ambient property changes help but require careful testing. The need to accommodate these nuances can lead to a more complex implementation than initially anticipated .

Linking external resources in Delphi requires using the {$R file} directive to embed resources like bitmaps directly in the library. This ensures that design-time assets such as icons are appropriately displayed. Care must be taken in managing resource identifiers to avoid conflicts and ensure that these assets are properly rendered. Resource files need updating with the IDE's inherent limitations across versions, making manual adjustments potentially necessary .

TActiveXComponent is a descendant of TActiveXControl, designed specifically for invisible component scenarios. Unlike TActiveXControl, TActiveXComponent focuses on non-visual behavior and includes mechanisms to display a bitmap only during design time, hiding the control during runtime. This is particularly useful for components like timers or loggers that don't require a visual interface at runtime .

The 'DefinePropertyPages' method in TMyInvisibleComponentX is used to set up custom property pages, enhancing interaction through property sheets within an IDE. 'EventSinkChanged' updates the internal event interface, ensuring that when event sinks are swapped or modified, active event handlers continue to operate correctly by re-establishing links to the new event interface .

The 'fUserMode' property affects rendering by determining whether the component operates in user mode (runtime) or design mode. In design mode, the setting influences visibility, causing components to display their design-time interface (icon or bitmap) on IDE forms. During runtime, it dictates that these visual elements remain hidden, optimizing the component as functionally non-visual as expected for Runtime .

Modifying the *_TLB.PAS file poses challenges because the file is regenerated by the IDE upon saving the type library, overwriting manual changes. This can lead to a loss of custom modifications intended to optimize the component's behavior or appearance. To address this, developers should script necessary transformations as part of the build process or use version-control systems to manage custom patches that need reinstating after IDE regeneration .

ActiveX component architecture in Delphi accommodates suppression of obsolete properties by changing the ancestor class from TOleControl to a custom class such as TOleComponent, which hides unwanted inherited properties. Subsequently, property definitions are altered in the TLB file to refine user's interaction with visible properties during design-time .

You might also like