Authorware的外部消息接口
对于开发authorware的UCD来说,最困难的就是如何截取authorware在运行过程中对我们有用的消息,C++程序员可能会毫不犹豫的说:使用钩子函数吧,把消息一一勾出;dephi程序员可能会说:使用dephi的消息触发器吧;VB程序员说:使用窗口回调函数吧;C++bulider程序员会说:DEPHI兄弟怎么说我就怎么做;VFP程序员会说:?????????????(有没有搞错?)其实对于接收处理消息,dephi是最得心应手的。但归结起来总共有三种方法:
1 使用dephi本身的消息触发器功能 但该功能只能被窗体和控件使用并不适合接收外部 程序的消息
2 使用窗口子类化的方法。 也即使用窗口回调函数,通过向指定窗口插入一个合法的窗口过程来接收并处理消息
3 使用系统钩子函数。系统钩子函数的好处是可以对当前所有的应用程序进行监视,可以获取你想得到的消息,据我所知,有个著名的系统工具“键盘幽灵”就使用了该技术。系统钩子主要用来监视键盘和鼠标消息。
在这里,我将通过第二种和第三种方法来举例说明如何接收处理authorware的消息。
一 窗口子类化技术
当一个windows应用程序运行后,该程序就建立了一个窗口过程,用于接收处理消息,当我们要在程序中处理一个在主窗口过程中未被处理的消息时,就可以再建立一个窗口过程使我们能够处理我们想要处理的消息。对于authorware这样一个二次开发平台来说,我们不可能在authorware程序中主动去编译我们的窗口过程,因为我们不是authorware的开发人员,而且authorware也不是一个可视化程序开发平台,它只是一个多媒体快速开发工具,幸好它提供了支持动态连接库dll的接口,也即UCD,这就给我们这些所谓第三方开发人员借助第三方开发工具动手的好机会,下面我就本人作的一个例子来简单说明一下怎样利用窗口子类化技术截取authorware中的消息。
这个例子的作用是:运行后使authorware程序具有屏保的功能。
分析:一个屏保至少应具有这样一些特点:
1 它必须全屏幕运行,和当前分辨率无关,而且无标题栏,菜单栏
2 它必须隐藏鼠标,在退出后必须能恢复鼠标
3 它必须能够响应鼠标和键盘消息,且响应之后必须关闭本程序
4 它必须只能运行一次,不能同时运行两个程序
在这里,第三条是是体现窗口子类化技术的要点。
该函数实现代码如下:
function X_coolscrsav(awparam:AWPARAM_PTR):boolean;stdcall;//cool屏保
var
oldpoint:Tpoint;
screenheight,screenwidth:integer;
oldstyle:longint;
hmenu:Thandle;
begin
awhandle:=awparam.hwnd;
if awparam.authoring=true then
begin
messagebox(awhandle,'请打包后使用!','提示',MB_OK);//如果当前在设计期状态则不运行
exit;
result:=false;
end;
getcursorpos(oldpoint);
oldx:=oldpoint.x;
oldy:=oldpoint.y; //取得当前鼠标指针位置
screenheight:=screen.Height;
screenwidth:=screen.Width; //利用screen对象获取当前屏幕宽和高
showcursor(false); //隐藏鼠标
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,0,0,0) ; //向系统通知屏保已//经运行,以防止运行多个实例
ShowWindow(FindWindow('Shell_TrayWnd', '', SW_HIDE); //隐藏任务栏
oldstyle:=getwindowlong(awhandle,GWL_EXSTYLE);
oldstyle:=oldstyle and not WS_SYSMENU and not WS_CAPTION;
setwindowlong(awhandle,GWL_STYLE,oldstyle); //去除标题栏和菜单栏(如果有的话)
setwindowpos(awhandle,HWND_TOPMOST,0,0,screenwidth,screenheight,SWP_SHOWWINDOW); //设置窗口为全屏
prewndproc:=pointer(getwindowlong(awhandle,GWL_WNDPROC));//获取原窗口过程指针
oldwndproc:=pointer(setwindowlong(awhandle,GWL_WNDPROC,longint(@newwinproc)));//设置新的窗口过程
result:=true;
end;
新建窗口过程:
function newwinproc(handle:Thandle;msg,wparam,lparam:longint):longint;stdcall;
var
ProcessID,cpid : Cardinal;
newx,newy:integer;
newpoint:Tpoint;
dx,dy:integer;
begin
getcursorpos(newpoint);
newx:=newpoint.x ;
newy:=newpoint.y ;
dx:=abs(newx-oldx);
dy:=abs(newy-oldy); //判断鼠标指针移动的距离
if ( (msg=WM_KEYUP) or (msg=WM_LBUTTONUP) or (msg=WM_RBUTTONUP) or (msg=WM_MBUTTONUP) or (dx>=5) or (dy>=5) ) then//这里就是响应消息的地方,如果有键盘消息或鼠标按下或指针移动距离超过5个像素点,则退出
begin
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,1,0,0) ;
ShowWindow(FindWindow('Shell_TrayWnd', '', SW_RESTORE);//还原任务栏
ProcessID := GetWindowThreadProcessID(awhandle ,@cpid);
TerminateProcess(OpenProcess(PROCESS_TERMINATE,false,cpid),1);
//因为考虑到authorware退出后有logo 画面,所以这里采用关闭句柄的办法退出
//否则就用下面的两行代码退出
// setwindowlong(handle,GWL_WNDPROC,longint(prewndproc));//将窗口过程还原到
原窗口过程
//sendmessage(handle,WM_COMMAND,SW_CLOSE);//向程序发退出消息
end;
result:=callwindowproc(oldwndproc,handle,msg,wparam,lparam); //窗口回调
end;
二 HOOK 技术 (钩子函数)
利用安装一个系统钩子同样能够对消息监视,它不同于窗口子类化的技术的是:它可以对系统中所有的窗口的消息进行监视,系统开销也较大一些,如果只是对authorware的窗口消息监视,最好就用子类化方法,不推荐使用,但为了了解,在这里还是举一个例子来说明一下。这里以xjapi.u32中的X_closebyrbutton函数举例。该函数的作用是如果用户在authorware程序中单击右键则退出,很显然我们要钩的消息就是鼠标右键按下(或抬起)的消息。先简要介绍一下需要用到的几个重要的windows api 函数(使用pascal语言描述):
SetWindowsHookEx(idHook:integer;HookProc:longint,HInstance:Hmode, dwThreadId:wORD):HHOOK;
作用:安装钩子
详细说明请参加windows SDK 帮助
MouseProc( nCode:integer; wParam, lParam:longint):longint;
作用:处理钩来的消息函数过程,它是个回调函数详细说明请参加windows SDK 帮助
CallNextHookEx( hhk: HHOOK; nCode:integer; wParam, lParam:longint):longint;
作用:传递钩子信息到下一个钩子链详细说明请参加windows SDK 帮助
UnHookWindowsHookEx(hook:HHOOK):boolean;
作用:卸下钩子
详细说明请参加windows SDK 帮助
下面是实现过程
给用户直接调用的函数:
var
awhandle:Thandle;
HookedAlready:Boolean;
Ourhook:HOOK;
……
function X_closebyRbutton(awparam:AWPARAM_PTR):boolean;stdcall;
begin
try
awhandle:=awparam.hwnd;//awhandle 必须作为全局变量声明
if HookedAlready then exit; //hookedalready 必须作为全局变量声明,作用是保证只安装//一次钩子
ourHook:=SetWindowsHookEx(WH_MOUSE,HookProc,HInstance,0);
//ourhook必须作为全局变量声明,这里开始安装一个鼠标消息钩子
HookedAlready:=True;//设置标志变量,标示钩子已安装
result:=true;
except
result:=false;
end;
end;
钩子回调函数过程:
function HookProc(Code:integer; wParam: longint; lParam: Longint):longint;stdcall;
begin
if (wParam=WM_RBUTTONUP) then //假如消息是右键按下
begin
if getforegroundwindow=awhandle then //假如当前工作窗口是authorware窗口
begin
UnHookWindowsHookEx(ourHook); //卸下钩子
HookedAlready:=False;; //恢复标志位
sendmessage(getforegroundwindow,WM_SYSCOMMAND,SC_CLOSE,0);//向当前窗口发送关闭消息
end;
end;
result:=CallNextHookEx(ourHook,Code,wParam,lParam);//否则钩下条消息
end;