自从SP2以后,DHTMLEdit被打上了补丁,delphi却没有相应地更新接口,就产生了错误。安装和一般使用都没问题,只是一用到DOM的时候就出错了。
Get_DOM是一个重要的函数,出错的原因是TOleControl必须要有IOleContainer的接口。
先讲一下如何在KOL中解决这个问题:
KOL中负责ActiveX的单元是ActiveXKOL.pas。打开ActiveXKOL.pas,在定义中加入以下定义:
TImpIOleContainer = class(TObject, IOleContainer)
private
m_cRef: UINT;
protected
{ IUnknown }
function
QueryInterface(const IID: TGUID; out Obj): HResult;
stdcall;
function _AddRef: Integer;
stdcall;
function _Release: Integer; stdcall;
public
{ IOleContainer }
function
ParseDisplayName(const bc: IBindCtx; pszDisplayName:
POleStr;
out chEaten: Longint; out
mkOut: IMoniker): HResult; stdcall;
function
EnumObjects(grfFlags: Longint; out Enum: IEnumUnknown): HResult;
stdcall;
function LockContainer(fLock: BOOL): HResult;
stdcall;
constructor Create;
destructor Destroy; override;
end;
在实现中加入以下代码:
function TImpIOleContainer._AddRef: Integer;
begin
inc(m_cRef);
Result := m_cRef;
end;
function TImpIOleContainer._Release: Integer;
begin
Dec(m_cRef);
Result := m_cRef;
if m_cRef = 0 then
Free;
end;
function TImpIOleContainer.EnumObjects(grfFlags:
Integer;
out Enum: IEnumUnknown):
HResult;
begin
Result := E_NOTIMPL;
end;
function TImpIOleContainer.LockContainer(fLock: BOOL):
HResult;
begin
Result := E_NOTIMPL;
end;
function TImpIOleContainer.ParseDisplayName(const bc:
IBindCtx;
pszDisplayName: POleStr; out chEaten:
Integer;
out mkOut: IMoniker): HResult;
begin
Result := E_NOTIMPL;
end;
function TImpIOleContainer.QueryInterface(const IID: TGUID; out
Obj):
HResult;
const
IID_IUnknown : TGUID = (
D1: $00000000; D2: $0000; D3: $0000; D4: ($C0, $00, $00, $00, $00,
$00,
$00, $46));
IID_IOleContainer : TGUID = (
D1:
$0000011B; D2: $0000; D3: $0000; D4: ($C0, $00, $00, $00, $00, $00,
$00, $46));
begin
if GetInterface(IID, Obj) then
begin
Result := S_OK;
Exit;
end;
if (Guidtostring(IID_IUnknown) =
Guidtostring(IID)) or
(Guidtostring(IID_IOleContainer) =
Guidtostring(IID)) then
begin
IOleContainer(Obj)
:= Self;
Result := S_OK;
self._AddRef;
end;
end;
constructor TImpIOleContainer.Create;
begin
inherited;
end;
destructor TImpIOleContainer.Destroy;
begin
inherited;
end;
这样就定义了一个IOleContainer的实现了。再加入使用代码:
找到函数:TOleCtlIntf.GetContainer,再改写函数代码:
const
IID_IOleContainer : TGUID = (
D1:
$0000011B; D2: $0000; D3: $0000; D4: ($C0, $00, $00, $00, $00,
$00,
$00, $46));
var
aCntr :
TImpIOleContainer;
begin
aCntr :=
TImpIOleContainer.Create;
Result :=
aCntr.QueryInterface(IID_IOleContainer, container);
end;
这样就可以了,再使用DOM的时候完全没问题了。原先的代码是不实现所以会出错。
===============================================
在delphi的VCL中也有同样的问题。
有两种方法解决这个问题:
1.TOleControl实现接口IOleContainer。
2.TOleControl.GetContainer中增加语句,使用IOleContainer。
第一种方法的实现:直接将TOleControl加上接口IOleContainer。
抄自:yahoo论坛上的。
Save a copy of OleCtrls.pas in your projects dir.
modify the
TOleControl definition - add interface IOleContainer - should
look
something like this:
TOleControl = class(TWinControl, IUnknown,
IOleClientSite,
IOleControlSite, IOleInPlaceSite, IOleInPlaceFrame,
IDispatch,
IPropertyNotifySink, ISimpleFrameSite, IOleContainer)
Add
the following to the protected section of
TOleControl
//IOleContainer
function EnumObjects(grfFlags: Longint;
out Enum: IEnumUnknown):
HResult; stdcall;
function LockContainer(fLock:
BOOL): HResult; stdcall;
function ParseDisplayName(const bc: IBindCtx;
pszDisplayName:
POleStr; out chEaten: Longint; out mkOut: IMoniker): HResult;
stdcall;
and the corresponding implementation
function
TOleControl.EnumObjects(grfFlags: Integer;
out Enum: IEnumUnknown):
HResult;
begin
Result := E_NOTIMPL;
end;
function
TOleControl.LockContainer(fLock: BOOL): HResult;
begin
Result :=
E_NOTIMPL;
end;
function TOleControl.ParseDisplayName(const bc:
IBindCtx;
pszDisplayName: POleStr; out chEaten: Integer;
out mkOut:
IMoniker): HResult;
begin
Result := E_NOTIMPL;
end;
finally
change TOleControl.GetContainer to
function TOleControl.GetContainer(out
container: IOleContainer):
HResult;
begin
container:= Self;
Result:=
S_OK;
end;
第二种方法:创建一个类实现IOleContainer,然后在TOleControl.GetContainer中使用这个类。
//Create a class with IOleContainer
interface
TImpIOleContainer = class(TObject,
IOleContainer)
private
m_cRef: UINT;
protected
{ IUnknown
}
function QueryInterface(const IID: TGUID; out Obj): HResult;
stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer;
stdcall;
public
{ IOleContainer }
function ParseDisplayName(const bc:
IBindCtx; pszDisplayName: POleStr;
out chEaten: Longint; out mkOut:
IMoniker): HResult; stdcall;
function EnumObjects(grfFlags: Longint; out
Enum: IEnumUnknown):
HResult;
stdcall;
function LockContainer(fLock:
BOOL): HResult; stdcall;
constructor Create;
destructor Destroy;
override;
end;
//=======
{ TImpIOleContainer }
function
TImpIOleContainer._AddRef: Integer;
begin
inc(m_cRef);
Result :=
m_cRef;
end;
function TImpIOleContainer._Release:
Integer;
begin
Dec(m_cRef);
Result := m_cRef;
if m_cRef = 0
then
Free;
end;
function TImpIOleContainer.EnumObjects(grfFlags:
Integer;
out Enum: IEnumUnknown): HResult;
begin
Result :=
E_NOTIMPL;
end;
function TImpIOleContainer.LockContainer(fLock: BOOL):
HResult;
begin
Result := E_NOTIMPL;
end;
function
TImpIOleContainer.ParseDisplayName(const bc: IBindCtx;
pszDisplayName:
POleStr; out chEaten: Integer;
out mkOut: IMoniker):
HResult;
begin
Result := E_NOTIMPL;
end;
function
TImpIOleContainer.QueryInterface(const IID: TGUID; out
Obj):
HResult;
const
IID_IUnknown : TGUID = (
D1: $00000000; D2:
$0000; D3: $0000; D4: ($C0, $00, $00, $00, $00, $00,
$00,
$46));
IID_IOleContainer : TGUID = (
D1: $0000011B; D2: $0000; D3: $0000;
D4: ($C0, $00, $00, $00, $00, $00,
$00, $46));
begin
if
GetInterface(IID, Obj) then begin
Result := S_OK;
Exit;
end;
if (Guidtostring(IID_IUnknown) =
Guidtostring(IID))
or
(Guidtostring(IID_IOleContainer) = Guidtostring(IID)) then
begin
IOleContainer(Obj) := Self;
Result :=
S_OK;
self._AddRef;
end;
end;
//========= modify
TOleControl.GetContainer
function TOleControl.GetContainer(out container:
IOleContainer):
HResult;
const
IID_IOleContainer : TGUID = (
D1:
$0000011B; D2: $0000; D3: $0000; D4: ($C0, $00, $00, $00, $00, $00,
$00,
$46));
var
aCntr : TImpIOleContainer;
begin
aCntr :=
TImpIOleContainer.Create;
Result := aCntr.QueryInterface(IID_IOleContainer,
container);
end;
--
本文章使用开源内容管理kicoy发布