独家秘方-KOL中如何使用DHTMLEdit(兼顾VCL)

3 views
Skip to first unread message

magi...@gmail.com

unread,
May 24, 2006, 11:35:04 PM5/24/06
to kicoy开发论坛

DHTMLEdit是MS多年来提供的一个HTML编辑器,随着IE的蔓延而到处传播,基本上IE5以上就已经有了,作为一个activex,delphi也支持它。


自从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发布

Reply all
Reply to author
Forward
0 new messages