承接上文。
在完成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;
}