http://www.sufeinet.com/plugin.php?id=keke_group

苏飞论坛

 找回密码
 马上注册

QQ登录

只需一步,快速开始

分布式系统框架(V2.0) 轻松承载百亿数据,千万流量!讨论专区 - 源码下载 - 官方教程

HttpHelper爬虫框架(V2.7-含.netcore) HttpHelper官方出品,爬虫框架讨论区 - 源码下载 - 在线测试和代码生成

HttpHelper爬虫类(V2.0) 开源的爬虫类,支持多种模式和属性 源码 - 代码生成器 - 讨论区 - 教程- 例子

查看: 14737|回复: 5

[基类库] winform窗体的最小化和还原,一键切换。如何获取当前句柄,并发送消息。

[复制链接]
发表于 2015-6-17 01:13:18 | 显示全部楼层 |阅读模式
1金钱
我看了下博客园提供的一些方案,由于窗体最小化和最大化,窗体的句柄会发生变化,所以,按热键之后,会有可能无效。因为句柄发生了变化。


那么,如果在快捷键按下时候,准确获得winform的句柄,并使得之前最小化的窗体,恢复之前的状态呢。

[C#] 纯文本查看 复制代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Collections;

namespace 丝材管控
{
	public partial class Form1 : Form
	{

		#region
		//创建NotifyIcon对象 
		NotifyIcon notifyicon = new NotifyIcon();
		//创建托盘图标对象 
		Icon ico = new Icon("snow.ico");
		//创建托盘菜单对象 
		ContextMenu notifyContextMenu = new ContextMenu();
		#endregion


		public Form1()
		{
			InitializeComponent();


		}

		public void OnHotkey(int HotkeyID) //Alt +F3 显示和隐藏窗体
		{
			if (HotkeyID == Hotkey.Hotkey1)
			{
				if (this.Visible == true)
					this.Visible = false;
				else

					 this.Visible = true;
				showForm();
			}
			else
			{
				this.Visible = false;
			}
		}

		public  void showForm()
		{
			//判断是否已经最小化于托盘 
			//if (WindowState == FormWindowState.Minimized)
			//{
				//还原窗体显示 
				WindowState = FormWindowState.Normal;
				//激活窗体并给予它焦点 
				this.Activate();
				//任务栏区显示图标 
				this.ShowInTaskbar = true;
				//托盘区图标隐藏 
				notifyicon.Visible = false;
			//}
		}
		private void Form1_FormClosing(object sender, FormClosingEventArgs e)
		{
			// 取消关闭窗体
			e.Cancel = true;

			// 将窗体变为最小化
			this.WindowState = FormWindowState.Minimized;
		}



		private void button1_Click(object sender, EventArgs e)
		{
			timer1.Start();
			button1.Enabled = false;
			comboBox1.Enabled = false;
			dateTimePicker1.Enabled = false;
			DateTime action = DateTime.Now;
			TimeSpan ts = DateTime.Now - dateTimePicker1.Value;
			int m = (Int32)ts.TotalMinutes;
			int TotalHour = judgeHour();
			int RsultMinutes = TotalHour * 60 - m;

			int H = (int)(RsultMinutes / 60);
			int M = RsultMinutes % 60;
			string Text = H + "小时" + M + "分钟";
			if (comboBox1.Text == "")
			{
				toolStripStatusLabel2.Text = "--";
				MessageBox.Show("请选择丝材!", "Message:");
			}
			else
				toolStripStatusLabel2.Text = Text;

			if (H < 0)
			{
				MessageBox.Show("不能为负数!", "Message:");
			}

			if (H > TotalHour)
			{
				MessageBox.Show("有效期不能大于" + TotalHour + "小时!", "Message:");
			}

			if (M < 0)
			{
				MessageBox.Show("丝材已经过期,请及时更换丝材!", "Warning!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
			}

		}

		public int judgeHour()
		{
			int Hour = 0;
			string caseSwitch = comboBox1.Text;
			switch (caseSwitch)
			{
				case "Cu(铜线)":
					Hour = 72;
					break;
				case "Pd(镀钯线)":
					Hour = 96;
					break;
				case "Al(合金线)":
					Hour = 96;
					break;
			}
			return Hour;
		}



		private void timer1_Tick(object sender, EventArgs e)
		{
			DateTime action = DateTime.Now;
			TimeSpan ts = DateTime.Now - dateTimePicker1.Value;
			int m = (Int32)ts.TotalMinutes;
			int TotalHour = judgeHour();
			int RsultMinutes = TotalHour * 60 - m;

			int H = (int)(RsultMinutes / 60);
			int M = RsultMinutes % 60;
			string Text = H + "小时" + M + "分钟";
			if (comboBox1.Text == "")
			{
				toolStripStatusLabel2.Text = "--";
			}
			else
				toolStripStatusLabel2.Text = Text;

			if ((H == 0) && (M == 0))
			{
				MessageBox.Show("丝材已经过期,请及时更换丝材!", "Warning!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

			}
		}

		private void Form1_Load(object sender, EventArgs e)
		{
			Hotkey hotkey;
			hotkey = new Hotkey(this.Handle);
			Hotkey.Hotkey1 = hotkey.RegisterHotkey(System.Windows.Forms.Keys.F3, Hotkey.KeyFlags.MOD_ALT);   //定义快键(Alt+ F3)
			hotkey.OnHotkey += new HotkeyEventHandler(OnHotkey);
			//设置鼠标放在托盘图标上面的文字 
			this.notifyIcon1.Text = "丝材管控";
		}

		private void 查看记录ToolStripMenuItem_Click(object sender, EventArgs e)
		{
			Environment.Exit(0);
		}

		private void button2_Click(object sender, EventArgs e)
		{
			button1.Enabled = true;
			comboBox1.Enabled = true;
			dateTimePicker1.Enabled = true;
			toolStripStatusLabel2.Text = "--";
			timer1.Stop();
		}

		//private void Form1_SizeChanged(object sender, EventArgs e)
		//{
		//	//判断是否选择的是最小化按钮 
		//	if (WindowState == FormWindowState.Minimized)
		//	{
		//		//托盘显示图标等于托盘图标对象 
		//		//注意notifyIcon1是控件的名字而不是对象的名字 
		//		notifyIcon1.Icon = ico;
		//		//隐藏任务栏区图标 
		//		this.ShowInTaskbar = false;
		//		//图标显示在托盘区 
		//		notifyicon.Visible = true;
		//	}
		//}

		private void notifyIcon1_DoubleClick(object sender, EventArgs e)
		{
			//判断是否已经最小化于托盘 
			if (WindowState == FormWindowState.Minimized)
			{
				//还原窗体显示 
				WindowState = FormWindowState.Normal;
				//激活窗体并给予它焦点 
				this.Activate();
				//任务栏区显示图标 
				this.ShowInTaskbar = true;
				//托盘区图标隐藏 
				notifyicon.Visible = false;
			}
		}


		private void 切换ToolStripMenuItem_Click(object sender, EventArgs e)
		{
			
			//判断是否选择的是最小化按钮 
			if (this.Visible == true)
				this.Visible = false;
			else

				this.Visible = true;
		}

		

	
	}

	#region 获取当前程序窗体句柄
	class CurrentProcess
	{
		private static Hashtable processWnd = null;

		public delegate bool WNDENUMPROC(IntPtr hwnd, uint lParam);

		static CurrentProcess()
		{
			if (processWnd == null)
			{
				processWnd = new Hashtable();
			}
		}

		[DllImport("user32.dll", EntryPoint = "EnumWindows", SetLastError = true)]
		public static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, uint lParam);

		[DllImport("user32.dll", EntryPoint = "GetParent", SetLastError = true)]
		public static extern IntPtr GetParent(IntPtr hWnd);

		[DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId")]
		public static extern uint GetWindowThreadProcessId(IntPtr hWnd, ref uint lpdwProcessId);

		[DllImport("user32.dll", EntryPoint = "IsWindow")]
		public static extern bool IsWindow(IntPtr hWnd);

		[DllImport("kernel32.dll", EntryPoint = "SetLastError")]
		public static extern void SetLastError(uint dwErrCode);

		public IntPtr GetCurrentWindowHandle(Process process)
		{
			IntPtr ptrWnd = IntPtr.Zero;
			uint uiPid = (uint)process.Id;  // 进程 ID
			object objWnd = processWnd[uiPid];

			if (objWnd != null)
			{
				ptrWnd = (IntPtr)objWnd;
				if (ptrWnd != IntPtr.Zero && IsWindow(ptrWnd))  // 从缓存中获取句柄
				{
					return ptrWnd;
				}
				else
				{
					ptrWnd = IntPtr.Zero;
				}
			}

			bool bResult = EnumWindows(new WNDENUMPROC(EnumWindowsProc), uiPid);
			// 枚举窗口返回 false 并且没有错误号时表明获取成功
			if (!bResult && Marshal.GetLastWin32Error() == 0)
			{
				objWnd = processWnd[uiPid];
				if (objWnd != null)
				{
					ptrWnd = (IntPtr)objWnd;
				}
			}

			return ptrWnd;
		}

		private static bool EnumWindowsProc(IntPtr hwnd, uint lParam)
		{
			uint uiPid = 0;

			if (GetParent(hwnd) == IntPtr.Zero)
			{
				GetWindowThreadProcessId(hwnd, ref uiPid);
				if (uiPid == lParam)    // 找到进程对应的主窗口句柄
				{
					processWnd[uiPid] = hwnd;   // 把句柄缓存起来
					SetLastError(0);    // 设置无错误
					return false;   // 返回 false 以终止枚举窗口
				}
			}

			return true;
		}
	}
	
	#endregion
}



1. 开通SVIP会员,免费下载本站所有源码,不限次数据,不限时间
2. 加官方QQ群,加官方微信群获取更多资源和帮助
3. 找站长苏飞做网站、商城、CRM、小程序、App、爬虫相关、项目外包等点这里
 楼主| 发表于 2015-6-18 17:41:14 | 显示全部楼层
本帖最后由 我是MT 于 2015-6-18 17:44 编辑

源码.rar是我自己的,我用了全局钩子实现热键切换winform窗体的 显示和隐藏。

key preview.rar是老外的源代码,我改写了下。同样的F2快捷键实现form窗体的 显示和隐藏。

为何我的就出现了错误呢,而老外的这个代码不会出现错误。  
错误的原因是 : 委托对象keyboardHookProc  被垃圾回收机制给回收了。 根据网络上网友的帖子,应该要把这个委托扔到全局class里面作为其成员,才不会导致垃圾回收。  自己由于可能语法基础薄弱吧。第一次遇到这个情况。 不知道如何解决了。

源码都附上。 劳烦看下。  两个源码都是一样的引入,为何老外的那个就不会出错,我的就出错了 。
QQ截图20150618173451.png


补充内容 (2015-6-18 18:04):
globalKeyboardHook+keyboardHookProc::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。

补充内容 (2015-6-19 02:41):
熬夜到凌晨3点钟,终于无奈之下 google到了答案:自己尝试了3个钟头无果。这个英文得好好分下了。http://stackoverflow.com/questio ... rdhook-was-detected

源码.rar

217.27 KB, 下载次数: 40, 下载积分: 金钱 -1

key preview.rar

74.59 KB, 下载次数: 33, 下载积分: 金钱 -1

回复

使用道具 举报

 楼主| 发表于 2015-6-19 02:56:42 | 显示全部楼层

搞了一宿,终于搞定了全局钩子被释放回收的问题。  还是借鉴了老外的经验。
这里附上文本,里面带了链接地址和详细的代码。
以后如果有人遇到类似的问题,希望可以从这里获得灵感。

附上完美解决方案.txt

924 Bytes, 下载次数: 71, 下载积分: 金钱 -1

回复

使用道具 举报

发表于 2015-6-17 08:22:37 | 显示全部楼层
听说过老板键吗、查下Api设置一下就行了
回复

使用道具 举报

 楼主| 发表于 2015-6-17 20:18:54 | 显示全部楼层
站长苏飞 发表于 2015-6-17 08:22
听说过老板键吗、查下Api设置一下就行了

OK。昨晚查了些资料,基本都是用API的。但还是会有bug   
回复

使用道具 举报

发表于 2015-6-18 08:14:17 | 显示全部楼层
我是MT 发表于 2015-6-17 20:18
OK。昨晚查了些资料,基本都是用API的。但还是会有bug

什么Bug
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 马上注册

本版积分规则

QQ|手机版|小黑屋|手机版|联系我们|关于我们|广告合作|苏飞论坛 ( 豫ICP备18043678号-2)

GMT+8, 2024-11-24 06:06

© 2014-2021

快速回复 返回顶部 返回列表