最近一个项目需要程序能动态的创建ActiveX组件,并在当前窗口显示出来,google了一下,未能找到前辈们的指点,就只能自己动手了,研究了一下Delphi中ActiveX相关单元的源码后,自己编写了一个类,可以实现动态创建ActiveX组件,放在这里自娱自乐一下,也免后来者重蹈我的覆辙。
unit DynamicOleControl;
interface
uses Windows, Classes, ActiveX, OleCtrls, ComObj;
type
TDynamicOleControl = class(TOleControl)
private
FClassID: TGUID;
FIntf: IUnknown;
function GetControlInterface: IUnknown;
protected
procedure CreateControl;
procedure InitControlData; override;
public
constructor CreateFromClassID(AOwner: TComponent; AClassID: TGUID); overload;
constructor CreateFromClassID(AOwner: TComponent; AClassID: string); overload;
constructor CreateFromProgID(AOwner: TComponent; AProgID: string);
property ControlInterface: IUnknown read GetControlInterface;
property DefaultInterface: IUnknown read GetControlInterface;
published
property Anchors;
end;
implementation
constructor TDynamicOleControl.CreateFromClassID(AOwner: TComponent;
AClassID: TGUID);
begin
FClassID := AClassID;
inherited Create(AOwner);
end;
constructor TDynamicOleControl.CreateFromClassID(AOwner: TComponent; AClassID: string);
begin
FClassID := StringToGUID(AClassID);
inherited Create(AOwner);
end;
constructor TDynamicOleControl.CreateFromProgID(AOwner: TComponent;
AProgID: string);
begin
FClassID := ProgIDToClassID(AProgID);
inherited Create(AOwner);
end;
procedure TDynamicOleControl.InitControlData;
const
CControlData: TControlData2 = (
ClassID: '';
EventIID: '';
EventCount: 0;
LicenseKey: nil;
Flags: $00000000; //$0000001D
Version: 401
);
begin
CopyMemory(@CControlData.ClassID, @FClassID, SizeOf(TGUID));
ControlData := @CControlData;
end;
procedure TDynamicOleControl.CreateControl;
procedure DoCreate;
begin
FIntf := IUnknown(OleObject) as IUnknown;
end;
begin
if FIntf = nil then DoCreate;
end;
function TDynamicOleControl.GetControlInterface: IUnknown;
begin
CreateControl;
Result := FIntf;
end;
end.
例子程序运行效果如下图所示:
DynamicOleControl.pas单元的使用比较简单,该例子的源码如下,大家一看就明白:
unit MainUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DynamicOleControl, StdCtrls, Buttons, ExtCtrls, ComObj;
type
TMainForm = class(TForm)
pnl1: TPanel;
pnlContainer: TPanel;
lbl1: TLabel;
edtClassID: TEdit;
btnLoad: TBitBtn;
btnFree: TBitBtn;
Label1: TLabel;
edtProgID: TEdit;
Label2: TLabel;
procedure btnFreeClick(Sender: TObject);
procedure btnLoadClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
FMyOleControl: TDynamicOleControl;
procedure FreeOleControl;
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
procedure TMainForm.FormCreate(Sender: TObject);
begin
FMyOleControl := nil;
end;
procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FreeOleControl;
end;
procedure TMainForm.FreeOleControl;
begin
if Assigned(FMyOleControl) then
FreeAndNil(FMyOleControl);
end;
procedure TMainForm.btnFreeClick(Sender: TObject);
begin
FreeOleControl;
end;
procedure TMainForm.btnLoadClick(Sender: TObject);
begin
FreeOleControl;
try
if Trim(edtClassID.Text) <> '' then
FMyOleControl := TDynamicOleControl.CreateFromClassID(Self,
Trim(edtClassID.Text))
else if Trim(edtProgID.Text) <> '' then
FMyOleControl := TDynamicOleControl.CreateFromProgID(Self,
Trim(edtProgID.Text));
if Assigned(FMyOleControl) then
begin
pnlContainer.InsertControl(FMyOleControl);
FMyOleControl.Align := alClient;
end;
except
on e: EOleSysError do
Application.MessageBox(PChar(e.Message), '错误', MB_OK + MB_ICONERROR);
end;
end;
end.
后记:
最近忙得有点天昏地暗,以后有时间再封装一下对动态加载后的ActiveX组件的相关操作方法。