有谁知道ActiveX控件DHTML Editor的各种参数的意义和使用方法?快救救我吧!(100分)

L

luket

Unregistered / Unconfirmed
GUEST, unregistred user!
我有它的SDK,但没讲到详细的资料,例如我想插入表格,操作表格单元格等等,很多参数都没说明,有谁知道ExecCommand()方法的各种参数,请告诉我!另外,有其他的资料吗?请告诉我网址或EMAIL给我!
谢谢!!!
 
S

snake

Unregistered / Unconfirmed
GUEST, unregistred user!
教你一招,先用先察看一下DHTML Editor那个OCX的位置,可以在frontpage插入一个
activex时看见他的ocx位置,接着用delphi把那个ocx打开,就可以看见他各种属性
方法和参数,至于怎么用,自己看着办
 

温柔一刀

Unregistered / Unconfirmed
GUEST, unregistred user!
这是个插入表格的例子:

procedure TForm1.btnInsertTableClick(Sender: TObject);
var
insertTableParam: DEInsertTableParam;
ovInsertTableParam: OleVariant;
begin
insertTableParam := CreateComObject(Class_DEInsertTableParam) as IDEInsertTableParam;

insertTableParam.NumRows := 4;
insertTableParam.NumCols := 3;
insertTableParam.TableAttrs := 'width=100%';
insertTableParam.CellAttrs := ' bgColor="blue" noWrap';

ovInsertTableParam := OleVariant(insertTableParam);
DHTMLEdit1.ExecCommand(DECMD_INSERTTABLE, OLECMDEXECOPT_DODEFAULT, ovInsertTableParam);
end;

另外这里有一篇文章:
http://www.delphizine.com/features/1999/08/di199908rl_f/di199908rl_f.asp
讲的相当详细了,还有全部源代码的例子。

另:我回去你另外几个帖子“回答”这个问题,希望不要吝啬哟 :)
 
L

luket

Unregistered / Unconfirmed
GUEST, unregistred user!
多人接受答案了。
 
L

luket

Unregistered / Unconfirmed
GUEST, unregistred user!
温柔一刀:
非常谢谢前面你对我几个总题的回答。你真是顶级的高手。
看一下这段代码,我去编译有很多错,怎么改,才能使DHTMLEDIT可以接受快捷键?
得蒙帮助,感激不尽!

Lost keys in the IE5 ActiveX controls - by




Abstract:Hooking the IWebBrowser and DHTML controls to properly handle keystrokes

The problem: If you import the Internet Explorer or Microsoft DHTML ActiveX controls into Delphi or C++Builder, the control does not respond to certain keystrokes (Tab, in the case of IE, and delete, in the case of DHTML).


The reasons for the problem: The problem occurs because of a combination of peculiar behavior on the part of the controls, and peculiar behavior on the part of the Delphi and C++Builder IDEs.


How the control is strange: The control believes that the keys in question should be treated as accelerators and wishes to handle them as such, rather than as Windows key down messages.


What Delphi and C++Builder are doing: TApplication catches all windows messages. As part of the processing of such messages, it allows windows contained within the application to respond to key messages themselves rather than use the default processing To allow VCL-wrapped windows to distinguish between messages passed to them by TApplication in the middle of message processing from messages which have been passed on after TApplication has given up on processing them, the VCL modifies the message and passes the modified message to the window via SendMessage. (The relevant code is in forms.pas: Application.IsKeyMsg).

When an ActiveX control is imported, it is wrapped by a descendant class of TOleControl (olectrls.pas). TOleControl hooks the window procedure
the hook catches the messages thrown by Application, modifies them back to their original state, and calls IOleInPlaceActiveObject.TranslateAccelerator, allowing the code to respond to accelerators.

With most controls, this works. Unfortunately, the dynamic nature of the IE controls causes a problem, in that the window which is recieving the messages is either a child or a grandchild of the window which has been subclassed. Their window procedures don't understand the messages they are recieving from TApplication (and so ignore them)
the accelerators never get translated
and the message that was intended by pressing tab or delete gets lost.

How Delphi 5 solves the problem: The problem was solved in Delphi 5 by modifying the behavior of TApplication.IsKeyMsg to walk the parent chain of a non-VCL window until a VCL window is encountered, and then throw the modified message at it. This allows the TOleControl wrapper to ask the control to translate the accelerator.


How you can solve the problem in C++Builder 4 or Delphi 4: The problem can be solved on an ad-hoc basis by dynamically subclassing the window procedures of the controls in question. (An earlier fix to the problem in Delphi5 involved modifying TOleControl to subclass the windows of all children created by the embedded Ole control
the problem with this approach was that, while the controls notify you verify their event interfaces when their children are destroyed and recreated, they do not pass such a notification through a standard Ole interface, so it was difficult to find a general-case mechanism for the container to know when to hook the child windows).


When to hook the window procedure: In the case of the WebBrowser control, a new child window is created whenever a new web page is accessed (and so the window procedure should be hooked in the OnNavigatComplete2 or the OnNewWindow2 event handlers). In the case of the DHTML control, there is usually only one child window whose creation is delayed until well past the creation of the control itself
manually hooking its window procedure in the form's OnActivate method should work).


How to get the handle for the window: The handle for the window that you want to subclass can be retrieved in one of two ways (one is generic, the other is not). You can get the handle for the window which was subclassed at the creation of the control by accessing the Handle method of the TOleControl descendant, using code that looks more or less like the following pascal code:


{these are members of Form1}

WebBrowser1 : TWebBrowser;
FFrameWndProcInstance: Pointer;
FFrameHwnd : HWND;
FFrameDefWndProc : Pointer;

function Form1.SubClassFrame;
var
Child : HWND;
begin
Child := GetWindow(WebBrowser1.Handle, GW_CHILD);
if Child <> 0 then
begin
Child := GetWindow(Child, GW_CHILD);
if (Child <>0) and (Child <> FFrameHwnd) then
{ don't bother subclassing if you've already got it subclassed }
begin
if FFrameWndProcInstance <> nil then
UnSubClassFrame;
FFrameHwnd := Child;
FFrameWndProcInstance := MakeObjectInstance(FrameWndProc);
FFrameDefWndProc := Pointer(GetWindowLong(FFrameHwnd, GWL_WNDPROC));
SetWindowLong(FFrameHwnd, GWL_WNDPROC, LongInt(FFrameWndProcInstance));
end;
end;
end;

function Form1.UnSubClassFrame;
begin
if (FFrameWndProcInstance <> nil and (FDefFrameWndProc) <> nil and (FFrameHwnd <> 0) then
begin
SetWindowLong(FFrameHwnd, GWL_WNDPROC, LongInt(FDefFrameWndProc));
FFrameWndProcInstance := nil;
FFrameHwnd := nil;
{ require the caller to set FDefFrameWndProc to nil so you can unsubclass and then call the default
proc when responding to WM_DESTROY events }
end;
end;
Alternately, you can ask the control to return to you an IOleInPlaceActiveObject interface, and query it for its window handle:
function Form1.SubClassFrame;
var
ActiveObject : IOleInPlaceActiveObject;
Child : HWND;
begin
if (WebBrowser1.DefaultDispatch.QueryInterface(IOleInPlaceActiveObject, ActiveObject) = S_OK) then
try
Child := ActiveObject.GetWindow;
if (Child <> nil) and (Child <> FFrameHwnd) then
begin
if FFrameWndProcInstance <> nil then
UnSubClassFrame;
FFrameHwnd := Child;
FFrameWndProcInstance := MakeObjectInstance(FrameWndProc);
FFrameDefWndProc := Pointer(GetWindowLong(FFrameHwnd, GWL_WNDPROC));
SetWindowLong(FFrameHwnd, GWL_WNDPROC, LongInt(FFrameWndProcInstance));
end;
finally
ActiveObject.Release;
end;
end;

function Form1.UnSubClassFrame;
var
ActiveObject: IOleInPlaceActiveObject;
begin
if (WebBrowser1.DefaultDispatch.QueryInterface(IOleInPlaceActiveObject, ActiveObject) = S_OK) then
try
if (FFrameWndProcInstance <> nil and (FDefFrameWndProc) <> nil and (FFrameHwnd <> 0) then
begin
SetWindowLong(FFrameHwnd, GWL_WNDPROC, LongInt(FDefFrameWndProc));
FFrameWndProcInstance := nil;
FFrameHwnd := nil;
{ require the caller to set FDefFrameWndProc to nil so you can unsubclass and then call the default
proc when responding to WM_DESTROY events }
end;
finally
ActiveObject.Release;
end;
end;
What the window procedure should do. The window procedure hook you install should, at a minimum, pass the key messages on to the ole control's accelerator treanslator, properly unhook itself in response to a WM_DESTROY message,and pass all other messages along to the default window procedure, as per the following example:
procedure Form1.FrameWndProc(var Message: TMessage);
var
WinMsg: TMsg;
ActiveObject : IOleInPlaceActiveObject;
begin
if (Message.Msg >= CN_BASE + WM_KEYFIRST)
and (Message.Msg <= CN_BASE + WM_KEYLAST) then
begin
WinMsg.HWnd := WebBrowser1.Handle;
WinMsg.Message := Message.Msg - CN_BASE;
WinMsg.WParam := Message.WParam;
WinMsg.LParam := Message.LParam;
WinMsg.Time := GetMessagTime;
WinMsg.Pt.X := $115DE1F1;
WinMsg.Pt.Y= $115DE1F1;
if (WebBrowser1.DefaultDispatch.QueryInterface(IOleInPlaceActiveObject, ActiveObject) = S_OK) then
try
if ActiveObject.TranslateAccelerator(WinMsg) = S_OK then
begin
Message.Result := 1;
WinMsg.Pt.X := $5ACC355;
end;
finally
ActiveObject.Release;
end;
if WinMsg.Pt.X = $5ACC355 then
Exit;
end;
with Message do
begin
case Msg of
WM_DESTROY:
begin
UnSubClassFrame;
CallWindowProc(FDefFrameWndProc, FFrameHwnd, Message.Msg, Message.WParam, Message.LParam);
FDefFrameWndProc := nil;
end;
end;
Result := CallWindowProc(FDefFrameWndProc, FFrameHwnd, Msg, WParam, LParam);
end;
end;
 

温柔一刀

Unregistered / Unconfirmed
GUEST, unregistred user!
这段代码bug真多,真不知道这种东西怎么能上borland community :)
估计是从BCB的代码翻译过来,而且还没做检查。

我把他改的能编译了,但仅仅能编译而已,是否实现功能不知道,
比如:subclassframe根本就没有调用到。
所以这些代码恐怕仅仅是个示例而已,直接拿去编程序估计后患无穷。 :)
我就不贴在这里了。

另外,这里面写的比较清楚,就是delphi5已经解决了这种问题,
不需要这种方法了。你是否用delphi 4?

 

温柔一刀

Unregistered / Unconfirmed
GUEST, unregistred user!
如果问题没解决,试验一下这段代码,
比你那段简单多了,而且应该能解决问题。

var
Form1: TForm1;
FOleInPlaceActiveObject: IOleInPlaceActiveObject;
SaveMessageHandler: TMessageEvent;

...

implementation

...

procedure TForm1.FormActivate(Sender: TObject);
begin
SaveMessageHandler := Application.OnMessage;
Application.OnMessage := MyMessageHandler;
end;

procedure TForm1.FormDeactivate(Sender: TObject);
begin
Application.OnMessage := SaveMessageHandler;
end;

procedure TForm1.FormClose(Sender: TObject
var Action: TCloseAction);
begin
Application.OnMessage := SaveMessageHandler;
FOleInPlaceActiveObject := nil;
end;

procedure TForm1.MyMessageHandler(var Msg: TMsg
var Handled: Boolean);
var
iOIPAO: IOleInPlaceActiveObject;
Dispatch: IDispatch;
begin
{ exit if we don't get back a DHTMLEdit object }
if DHTMLEdit1 = nil then
begin
Handled := False;
Exit;
end;

Handled := IsDialogMessage(DHTMLEdit1.Handle, Msg);

if (Handled) and (not DHTMLEdit1.Busy) then
begin
if FOleInPlaceActiveObject = nil then
begin
Dispatch := DHTMLEdit1.ControlInterface;
if Dispatch <> nil then
begin
Dispatch.QueryInterface(IOleInPlaceActiveObject, iOIPAO);
if iOIPAO <> nil then
FOleInPlaceActiveObject := iOIPAO;
end;
end;

if FOleInPlaceActiveObject <> nil then
if ((Msg.message = WM_KEYDOWN) or (Msg.message = WM_KEYUP)) and
((Msg.wParam = VK_BACK) or (Msg.wParam = VK_LEFT) or (Msg.wParam = VK_RIGHT)) then
//nothing - do not pass on Backspace, Left or Right arrows
else
FOleInPlaceActiveObject.TranslateAccelerator(Msg);
end;
end;
 
L

luket

Unregistered / Unconfirmed
GUEST, unregistred user!
温柔一刀:
这种方法我早就试过,不行。但在应用程序中可以。
我这里是一个ACTIVEX,也就是说,一个包含DHTMLEDIT的ActiveX控件,会有什么不同吗?
我发现:在MyMessageHandler中,加入一句
showmessage(inttostr(msg.wParam));
没有什么反应。根本没执行?
请你再帮我测试一下,假如解决了这个问题,我把我现有的所有大洋都给你。
谢谢!
 

温柔一刀

Unregistered / Unconfirmed
GUEST, unregistred user!
>>但在应用程序中可以
>>我这里是一个ACTIVEX,也就是说,一个包含DHTMLEDIT的ActiveX控件,会有什么不同吗?

当然不同了,因为出现此问题的根本原因就在于acviteX
不能接受到快捷键消息,因此在应用程序中加上这些代码,
“手工”把快捷键消息传递给dhtmlEdit就可以了。

然而,如果我没理解错你说的意思,你是把上面那段(我贴出来的)
代码修改了一下,放到了ActiveX中。但是你的activeX的Application变量是什么呢?
是个没有意义的值,并不是宿主程序的Application,
(实际上,如果你的activex被VB调用,根本也没有Application这个概念),
因此你写的MessageHandler也永远不会被执行。

其次,你现在作了一个activeX,它自身又存在同样的问题:
无法接受到快捷键,因而也就无法向下传递消息。因此前面你贴出来的
那篇文章的方法也不会成功,或者说,成功与否依赖于你的宿主程序是否
把消息传递给你的ActiveX,而不是依赖于你的ActiveX的功能。

总之,你必须使得你的ActiveX能够接收“外面的”快捷键消息,
从而传递给DHTMLEdit,而这不是你的ActiveX力所能及的。
(也许能用hook截获Windows按键消息来做处理,谁知道呢?)

我所能想到的就这些了,你可以继续请教其他高手,希望能有解决办法。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
1K
DelphiTeacher的专栏
D
顶部