使用Hook(钩子)阻止Flash启动浏览器打开URL_java

【文章目的】

在.net程序中嵌入flash文件,为了防止有人通过flash右键菜单中的“关于Macromedia”打开ie访问internet,或者flash中通过GetURL()方法打开浏览器直接访问internet

【解决方案】

使用Hook技术,截获flash在启动外部浏览器访问internet时向系统发送的消息,然后用线程将外部浏览器Kill掉

【编程手记】

开发工具:VS2005 Beta2,Flash版本为flash 8

为了达到禁止Flash打开浏览器的目的,从Hook(Hook不知道?天极里面资料很多的)入手,截获到Flash的相关事件信息,提前启动一个专杀浏览器的线程,使得Flash打开浏览器的瞬间关闭。我们先要找到Flash在播放电子杂志时候的一些相关数据,比如系统消息,发送给外部的消息结构为:

[StructLayout(LayoutKind.Sequential)]
    public struct CWPSTRUCT
    {
        public IntPtr lparam;
        public IntPtr wparam;
        public int message;
        public IntPtr hwnd;
    }
//在C#中使用钩子
public delegate int HookProc(int code, IntPtr wparam, ref CWPSTRUCT cwp);
        public static int WH_CALLWNDPROC = 0x004;
        //安装钩子的函数
        [DllImport("user32.dll", CharSet = CharSet.Auto,CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr SetWindowsHookEx(int type, HookProc hook, IntPtr instance, int threadID);
        //调用下一个钩子的函数
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int CallNextHookEx(IntPtr hookHandle, int code, IntPtr wparam, ref CWPSTRUCT cwp);
        //卸载钩子
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool UnhookWindowsHookEx(IntPtr hookHandle);
        //获取窗体线程ID
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern int GetWindowThreadProcessId(IntPtr hwnd, int ID);
        private HookProc hookProc;
        private IntPtr hookHandle = IntPtr.Zero;
    
这是打开Flash中一个含链接的事件时候截获的系统消息:
cwp.message =528 && cwp.wparam=513                                   //鼠标事件消息,在Flash上点击左右键盘都会发生
cwp.message =33cwp.lparam =33619969                                    
cwp.message =33cwp.lparam =33619969cwp.wparam=658836cwp.hwnd=724410
cwp.message =33cwp.lparam =33619969cwp.wparam=658836cwp.hwnd=658836
cwp.message =32cwp.lparam =33619969cwp.wparam=724410cwp.hwnd=724410
cwp.message =8cwp.lparam =0cwp.wparam=724410cwp.hwnd=527784
cwp.message =8cwp.lparam =0cwp.wparam=724410cwp.hwnd=527784
cwp.message =647cwp.lparam =527784cwp.wparam=24cwp.hwnd=658866       //当前窗口的得到或失去焦点消息
cwp.message =641cwp.lparam =-1073741809cwp.wparam=0cwp.hwnd=527784
cwp.message =641cwp.lparam =-1073741809cwp.wparam=0cwp.hwnd=658866
cwp.message =641cwp.lparam =-1073741809cwp.wparam=0cwp.hwnd=724374
cwp.message =647cwp.lparam =724410cwp.wparam=23cwp.hwnd=658866       //当前窗口得到或失去焦点信息
cwp.message =641cwp.lparam =-1073741809cwp.wparam=1cwp.hwnd=724410
cwp.message =641cwp.lparam =-1073741809cwp.wparam=1cwp.hwnd=658866
cwp.message =641cwp.lparam =-1073741809cwp.wparam=1cwp.hwnd=724374
cwp.message =992cwp.lparam =-1070940117cwp.wparam=855452cwp.hwnd=855452  //通知外部浏览器打开URL消息
cwp.message =992cwp.lparam =-1070940117cwp.wparam=855452cwp.hwnd=724374
cwp.message =992cwp.lparam =-1070940117cwp.wparam=855452cwp.hwnd=658866
cwp.message =992cwp.lparam =-1070940117cwp.wparam=855452cwp.hwnd=658836
cwp.message =996cwp.lparam =-1070940117cwp.wparam=462274cwp.hwnd=855452
从以上消息队列中可以找到Flash中相关事件的消息 message 的内容,查阅API的相关资料,经过测试可以得知,message=992 是想要截获的消息,截获到这个消息后,可以使用thread来kill IE的process(有人可能说这里可以直接将截获到的消息丢掉,实际上这是行不通的,有些钩子只能查看消息,不能修改消息,也不能通过返回非0值阻止消息继续传递。很不幸,我们用到的WH_CALLWNDPROC就是其中之一。MSDN里说得很清楚:After the hook procedure returns control to the system, the message is passed to the window procedure. 不过WH_GETMESSAGE钩子可以修改消息,大家可以试试看)。
       #region 阻止Flash打开URL
        private Thread killThread;
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            if (m.Msg == 992)
            {
                if (killThread != null)
                {
                    killThread.Abort();
                }
                killThread = new System.Threading.Thread(new System.Threading.ThreadStart(KillIE));
                killThread.IsBackground = true;
                killThread.Start();
            }
        }
        private void KillIE()
        {
            bool isKilled = false;
            while (!isKilled)
            {
                System.Threading.Thread.Sleep(10);
               //这里当然也可以是关闭firefox/maxthon 等其他浏览器
                Process[] processes = System.Diagnostics.Process.GetProcessesByName("iexplore");
                foreach (Process ps in processes)
                {
                    ps.Kill();
                    isKilled = true;
                    break;
                }
            }
        }
        #endregion

【小结】

本文只是在做项目的过程中碰到一个小的需求而进行的一个测验,解决方案有很多,目前为止这是我找到的一个性能比较高的方案,供大家参考,谢谢!