Delphi生成的ActiveX创建模板的研究--Com对象是如何创建的

Delphi 生成的XXX_TLB.pas文件中生成了一个类

TActiveFormX = class(TOleObject)

end;

另外在XXX_Impl.pas文件中同样生成了一个类:TActiveFormX,经过研究,这两个类的确是
一个是接口,一个是实现类。

前者TActiveFormX从TOleObject继承,并且实现了方法:

procedure TActiveFormX.InitControlData;
const
CEventDispIDs: array [0..8] of DWORD = (
$000000C9, $000000CA, $000000CB, $000000CC, $000000CD, $000000CE,
$000000CF, $000000D0, $000000D1);
CTFontIDs: array [0..0] of DWORD = (
$FFFFFE00);
CControlData: TControlData2 = (
ClassID: ‘{B90C2778-2158-48F5-A279-3A52BA87B423}’;
EventIID: ‘{8791E2BA-D57D-4CC9-91DA-81403D4E1144}’;
EventCount: 9;
EventDispIDs: @CEventDispIDs;
LicenseKey: nil (*HR:$80040154*);
Flags: $0000001D;
Version: 401;
FontCount: 1;
FontIDs: @CTFontIDs);
begin
ControlData := @CControlData;
TControlData2(CControlData).FirstEventOfs := Cardinal(@@FOnActivate) – Cardinal(Self);
end;

该方法负责定义这个OLE控件的类ID,事件接口ID,在TOleObject的方法TOleControl.createInstance中
则利用到了这些注册信息,创建COM对象:

procedure TOleControl.createInstance;
var
ClassFactory2: IClassFactory2;
LicKeyStr: WideString;

procedure LicenseCheck(Status: HResult; const Ident: string);
begin
if Status = CLASS_E_NOTLICENSED then
raise EOleError.createFmt(Ident, [ClassName]);
OleCheck(Status);
end;

begin
if not (csDesigning in ComponentState) and
(FControlData^.LicenseKey <> nil) then
begin
//创建COM对象,其中FControlData^.ClassID为子类定义的COM对象的ID
OleCheck(CoGetClassObject(FControlData^.ClassID, CLSCTX_INPROC_SERVER or
CLSCTX_LOCAL_SERVER, nil, IClassFactory2, ClassFactory2));
LicKeyStr := PWideChar(FControlData^.LicenseKey);
LicenseCheck(ClassFactory2.cr&#101;ateInstanceLic(nil, nil, IOleObject,
LicKeyStr, FOleObject), SInvalidLicense);
end else
LicenseCheck(Cocr&#101;ateInstance(FControlData^.ClassID, nil,
CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IOleObject,
FOleObject), SNotLicensed);
end;

COM对象的实现单元XXX_Impl.pas则定义了该COM对象的实现,并且创建了一个TActiveXControlFactory,
用于生成该COM对象:

initialization
TActiveFormFactory.cr&#101;ate(
ComServer,
TActiveFormControl,
TActiveFormX,
Class_ActiveFormX,
1,
”,
OLEMISC_SIMPLEFRAME or OLEMISC_ACTSlik&#101;LABEL,
tmApartment);
end.

因此前一个TActiveXForm 被称为OLEProxy,即Ole的调用网关。

COM系统CocreateInstance(IID)的时候会请求相应的TActiveFormFactory调用相应的createIntance方法。

830 次阅读

Singleton模式在多线程实现下的误区

今天使用多线程的方式写一个程序。非常不幸,碰到了死锁问题,最终发现:单例对象的创建时必须保证是同步的,否则多线程高并发情况下,可能创建出多个对象。并且导致错误。

以前写单例对象时使用的是下面的错误的写法:

public static SomeObject getInstance()
{
if (instance == null)
instance = new SomeObject();
return instance;
}

于是在多线程高并发的情况下,public static SomeObject getInstance()方法由于没有同步,被两个线程同时进入,这时候 instance 被创建两次。虽然最终instance对象只会保持有一个(因为只有一个对象句柄),但在这两个对象创建到销毁的一小段时间里边,就有可能发生死锁这样的情况。

所以一定要注意,创建Singleton对象时进行同步。另外考虑到public static SomeObject getInstance()可能是调用最频繁的,所以可以不加锁,只在创建方法上加锁。于是Singleton模式在多线程方式下,应当这样写:

public static synchronized SomeObject cr&#101;ateInstance()
{
if (instance == null)
instance = new SomeObject();
}

public static SomeObject getInstance()
{
if (instance == null)
cr&#101;ateInstance();

return instance;
}

这样在createInstance()不会被创建多个对象。

:)希望大家都很幸运,不会像我这样碰上这种让人郁闷的错误。

656 次阅读