winforms 嵌入ppt程序后,双击放大缩小功能

承接上文。

在完成ppt嵌入程序后,后来的我不满足于用ppt播放自带的右键菜单的全屏显示功能。

为什么不整个双击全屏恢复功能呢?

开始写代码后,发现,此时的ppt界面双击,根本触发不了panel的双击事件 

怎么办呢?开始查资料,最后终于找个到一个解决办法,那就是使用钩子 Win32Api.HookProc来捕获鼠标按下事件,关于Hook论坛有详解,看管自行摸索,就不放链接了。当然,对于钩子的代码我也说论坛复制粘贴的,hhhhh

放代码,下面是钩子的初始化

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TeachingSystem.Tools
{
    public class Win32Api
    {
        [StructLayout(LayoutKind.Sequential)]
        public class POINT
        {
            public int x;
            public int y;
        }
        [StructLayout(LayoutKind.Sequential)]
        public class MouseHookStruct
        {
            public POINT pt;
            public int hwnd;
            public int wHitTestCode;
            public int dwExtraInfo;
        }
        public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
        //安装钩子
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
        //卸载钩子
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern bool UnhookWindowsHookEx(int idHook);
        //调用下一个钩子
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
    }

    public class ToolMouseHook
    {
        private Point point;
        private Point Point
        {
            get { return point; }
            set
            {
                if (point != value)
                {
                    point = value;
                    if (MouseMoveEvent != null)
                    {
                        var e = new MouseEventArgs(MouseButtons.None, 0, point.X, point.Y, 0);
                        MouseMoveEvent(this, e);
                    }
                }
            }
        }
        private int hHook;
        private static int hMouseHook = 0;
        private const int WM_MOUSEMOVE = 0x200;
        private const int WM_LBUTTONDOWN = 0x201;
        private const int WM_RBUTTONDOWN = 0x204;
        private const int WM_MBUTTONDOWN = 0x207;
        private const int WM_LBUTTONUP = 0x202;
        private const int WM_RBUTTONUP = 0x205;
        private const int WM_MBUTTONUP = 0x208;
        private const int WM_LBUTTONDBLCLK = 0x203;
        private const int WM_RBUTTONDBLCLK = 0x206;
        private const int WM_MBUTTONDBLCLK = 0x209;

        public const int WH_MOUSE_LL = 14;
        public Win32Api.HookProc hProc;
        public ToolMouseHook()
        {
            this.Point = new Point();
        }
        /// <summary>
        /// 注册钩子
        /// </summary>
        /// <returns></returns>
        public int SetHook()
        {
            hProc = new Win32Api.HookProc(MouseHookProc);
            hHook = Win32Api.SetWindowsHookEx(WH_MOUSE_LL, hProc, IntPtr.Zero, 0);
            return hHook;
        }

        /// <summary>
        /// 卸载钩子
        /// </summary>
        public void UnHook()
        {
            Win32Api.UnhookWindowsHookEx(hHook);
        }

        /// <summary>
        /// 捕获鼠标按下事件
        /// </summary>
        /// <param name="nCode"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct));
            if (nCode < 0)
            {
                return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam);
            }
            else
            {
                MouseButtons button = MouseButtons.None;
                int clickCount = 0;
                switch ((Int32)wParam)
                {
                    case WM_LBUTTONDOWN:
                        button = MouseButtons.Left;
                        clickCount = 1;
                        MouseDownEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0));
                        break;
                    case WM_RBUTTONDOWN:
                        button = MouseButtons.Right;
                        clickCount = 1;
                        MouseDownEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0));
                        break;
                    case WM_MBUTTONDOWN:
                        button = MouseButtons.Middle;
                        clickCount = 1;
                        MouseDownEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0));
                        break;
                }

                this.Point = new Point(MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y);
                return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam);
            }
        }

        public delegate void MouseMoveHandler(object sender, MouseEventArgs e);
        public event MouseMoveHandler MouseMoveEvent;

        public delegate void MouseDownHandler(object sender, MouseEventArgs e);
        public event MouseDownHandler MouseDownEvent;
    }
}

在具体的调用中,会用到注册钩子SetHook和卸载钩子UnHook

初始化的时候,先注册钩子

/// <summary>
/// 检测鼠标事件的钩子
/// </summary>
private ToolMouseHook m_mh;


m_mh = new ToolMouseHook();
m_mh.SetHook();
m_mh.MouseDownEvent += mh_MouseDownEvent;//绑定事件

钩子使用完毕,卸载钩子

m_mh.UnHook();

钩子绑定的事件,此时去实现自己的鼠标按下事件

 #region =========Win32接口=======
[DllImport("user32.dll")]
public static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32", EntryPoint = "ShowWindow")]
private static extern bool ShowWindow(IntPtr hWnd, int fLag);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern IntPtr GetParent(IntPtr hWnd);
//获得顶层窗口
[DllImport("user32", EntryPoint = "GetForegroundWindow")]
private static extern IntPtr GetForegroundwindow();
[DllImport("user32.dll", EntryPoint = "GetWindowLong", CharSet = CharSet.Auto)]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
//设置窗口属性
[DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
//设置窗口位置
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
private static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter,
                                                int X, int Y, int cx, int cy, uint uFlags);


private const int SW_HIDE = 0;
private const int SW_SHOWNORMAL = 1;

private const int SW_SHOWMINIMIZED = 2;
private const int SW_SHOWMAXIMIZED = 3;
private const int SW_MAXIMIZE = 3;
private const int SW_SHOWNOACTIVATE = 4;
private const int SW_SHOW = 5;
private const int SW_MINIMIZE = 6;
private const int SW_SHOWMINNOACTIVE = 7;
private const int SW_SHOWNA = 8;
private const int SW_RESTORE = 9;
private const int WM_ClOSE = 0x10;//窗口关闭信息
private int HWND_TOPMOST = -1;
private int HWND_NOTOPMOST = -2;
private int HWND_BOTTOM = 1;
public const int WS_CAPTION = 0xC00000;
private const int HWND_TOP = 0x0;
private const int WM_COMMAND = 0x0112;
private const int WM_QT_PAINT = 0xC2DC;
private const int WM_PAINT = 0x000F;
private const int WM_SIZE = 0x0005;
private const int SWP_FRAMECHANGED = 0x0020;
#endregion

/// <summary>
/// ppt程序播放的句柄
/// </summary>
private IntPtr m_nAppHandle;


private void mh_MouseDownEvent(object sender, MouseEventArgs e)
{
     if (e.Button == MouseButtons.Left)
     {
          TimeSpan ts2 = new TimeSpan(DateTime.Now.Ticks);
          TimeSpan ts = ts2.Subtract(m_FirstTimeSpan).Duration();  // 时间差的绝对值
           m_FirstTimeSpan = new TimeSpan(DateTime.Now.Ticks);
           if (ts.TotalSeconds > 0.5)
            {
                 //两次单击时间间隔过长,不认为是双击
                 return;
            }
     }
     IntPtr ptr = GetForegroundwindow();
     //是否双击顶层资料,防止程序有其他顶层程序双击后仍然执行
     if (ptr == this.Handle)
     {   
           //执行了双击
           if (panelTeachContent.Location.X < e.Location.X
               && panelTeachContent.Location.X + panelTeachContent.Width > e.Location.X
               && panelTeachContent.Location.Y < e.Location.Y
               && panelTeachContent.Location.Y + panelTeachContent.Width > e.Location.Y)
           {
               Rectangle ret = Screen.GetWorkingArea(this);

               //窗口缩放前,先断掉app与软件的链接,防止panel的画布留有痕迹
               //SetParent(m_nAppHandle, IntPtr.Zero);
               if (panelTeachContent.Width < ret.Width 
                    && panelTeachContent.Height < ret.Height)
                {
                    
                    //放大屏幕
                    this.WindowState = FormWindowState.Maximized;

                    panelTeachContent.ClientSize = new Size(ret.Width, ret.Height);
                    panelTeachContent.Dock = DockStyle.Fill;
                    panelTeachContent.BringToFront();
                 }
                 else
                 {
                    //缩小
                    this.WindowState = FormWindowState.Normal;
                    panelTeachContent.ClientSize = m_primarySize;//primarySize即是控件的原始尺寸
                    panelTeachContent.Dock = DockStyle.None;

                 }
                //重新建立app和panel的连接
                //SetParent(m_nAppHandle, panelTeachContent.Handle);
                //放大或缩小程序界面 win32函数
                SetWindowPos(m_nAppHandle, HWND_TOP, 0, 0, panelTeachContent.Width, panelTeachContent.Height, SWP_FRAMECHANGED);
            }
      }
}

这样子就基本实现了双击ppt界面全屏和恢复的功能,但这样子会有瑕疵,在全屏时,全屏的图像时这样子的

 

 在红框出有不知名的边框,,研究一下后发现,这是因为放大了panel时,原本大小的panel,用SetWindowPos只是直接覆盖了放大了的panel,并没有清除panel原始尺寸的ppt程序。

所以须把上面代码中的两个setParent的注释放开

//窗口缩放前,先断掉app与软件的链接,防止panel的画布留有痕迹
SetParent(m_nAppHandle, IntPtr.Zero);

//重新建立app和panel的连接
SetParent(m_nAppHandle, panelTeachContent.Handle);

 然后效果如下

 完美实现了双击放大缩小的功能。。

这里补上文的瑕疵,在吧ppt程序界面移动到自己的panel中后,会出现有边框的现象,这里补两句代码:

private bool EmbedProcessEx(IntPtr nHwnd, Control control)
        {

            IntPtr hwnd = (IntPtr)nHwnd;
            //IntPtr hwnd = IntPtr.Zero;
            if (control == null || hwnd == IntPtr.Zero) return false;
            try
            {
                SetParent(hwnd, control.Handle);
                //MoveWindow(hwnd, 0, 0, control.Width, control.Height, true);
                //去除边框
                SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_CAPTION);
                //添加app界面到程序中
                SetWindowPos(hwnd, HWND_TOP, 0, 0, control.Width, control.Height, SWP_FRAMECHANGED);
            }
            catch (Exception ex)
            {
                return false;
            }
            return true;

        }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值