当前位置: 首页 > 编程日记 > 正文

Visual C#弹出窗口杀手

2002-11-19· ···ASPCool.com




弹出窗口杀手是一个可以自动关闭IE弹出窗口的程序,它工作在系统的托盘中,按照一定的间隔来检测IE窗口,然后关闭弹出窗体。最后,还提供了用热键来杀掉弹出窗口的功能。

  虽然已经有类似的用C++写的程序,但是本文讲述的是用C#来实现这些功能,并且本文所讲的方案在查找窗口上的方法要比更快一些。

  这是一个崭新的话题,在Internet上我们还可以看到许多类似的程序。但是我也还是要借这个机会来讲述一些下面的技术在C#中如何实现:

  系统托盘
  程序切换
  计时控件
  查找窗口
  系统热键

  生成一个系统托盘程序

  首先,产生一个新的C# Windows Form程序, 将NotifyIcon控件从工具箱中拖到窗体中,如下图所示:

  在C# windows Form程序中添加托盘

  为了保证系统托盘的图标和应用程序的图标一致,我们用一个共同的图标文件a.ico来设置系统托盘的图标和应用程序的图标。

  为了使程序不显示在工具栏上,我们可以设置窗体的visible属性为false. 这个可以在窗体属性窗口中直接实现。

  this.ShowInTaskbar = false;

  到目前为止,系统托盘已基本好了,但是我们还没有设置右键菜单,也没有使程序显示和隐藏的功能。

  程序切换

  首先,程序的主窗体可以根据不同的状态来选择显示或者是隐藏,除此之外,我们可以用WindowState设置窗体的状态:

public void HideApp()
{
this.WindowState = FormWindowState.Minimized;
Hide();
}
public void ShowApp()
{
Show();
this.WindowState = FormWindowState.Normal;
}

一个非常有趣的功能是让用户关闭窗体的时候程序并不是退出,为了实现这个功能,我们必须要重写窗体的OnClosing事件。

protected override void OnClosing(CancelEventArgs e)
{
// 用最小化来代替关闭操作d
e.Cancel = true;
// 最小化,并且隐藏窗体
this.WindowState = FormWindowState.Minimized;
Hide();
}
当然,我们必须要提供一个必须的退出方法.这个可以在托盘的右键菜单的exit中实现,
private void menu_App_Exit(object sender, System.EventArgs e)
{
NativeWIN32.UnregisterHotKey(Handle, 100);
//隐藏托盘
notifyIcon1.Visible = false;
Application.Exit();
}

添加右键菜单

  添加一个右键菜单和添加托盘基本一样,从工具箱中添加context menu就可以.右键菜单在你鼠标右键按下的时候是会自动弹出的。

  当设置好右键菜单以后,我们必要要根据不同的情况来启用或停用右键菜单,这个可以通过在菜单的BeforePopup设置。Enabled属性来实现。

private void menu_App_BeforePopup(object sender, System.EventArgs e)
{
if ( this.WindowState == FormWindowState.Minimized )
{
App_Show.Enabled = true;
App_Hide.Enabled = false;
}
else
{
App_Show.Enabled = false;
App_Hide.Enabled = true;
}
}




计时工具

  .Net Framework的 Timer能和系统的Win32 timer实现一样的功能。我们要做的就是设置一个timer,然后合理的设置属性。

m_Timer = new System.Timers.Timer(); // explicit namespace (Timer also in System.Threading)
m_Timer.Elapsed += new ElapsedEventHandler(OnTimerKillPopup);
m_Timer.Interval = m_nInterval; // for instance 3000 milliseconds
m_Timer.Enabled = true; // start timer

protected void OnTimerKillPopup(Object source, ElapsedEventArgs e)
{
m_Timer.Enabled = false; // pause the timer

FindPopupToKill();

m_Timer.Enabled = true;
}

本地win32窗体查找

  本程序的实现原理是这样,先检查所有的IE窗口标题,然后于已经有的列表来比较,如果有相同的,我们就关闭这个窗口。

  按照上面的方法,我们每n妙使用KillPopup()来检查。比较遗憾的是我们无法使用安全代码来完成所有的工作。我们可以使用 System.Diagnostics.Proces来检查所有的IE进程,然后得到主窗体。但是每一个IE进程可以打开好几个窗口,虽然每一个窗体都于一个进程相关,但是还没有办法来使每一个窗体于进程对应起来。

  一个可行的办法使用System.Diagnostics.Process列举出所有的运行的进程,然后System.Diagnostics.ProcessThreadCollection 来得到他们的.Threads属性,为了得到thread Id,我们使用Win32 API EnumThreadWindows(DWORD threadId,WNDENUMPROC lpfn,LPARAM lParam) 来实现,这是一个回调(call back)函数,他可以列举出于进程相关的窗体。当我们得到了窗体的句柄以后,我们可以使用另一个API函数 GetWindowText(HWND hwnd,/*out*/LPTSTR lpString,int nMaxCount)来得到窗体的标题,然后根据已经有的窗体,调用API函数SendMessage(HWND hWnd,int msg,int wParam,int lParam)来关闭窗口。下面使演示代码

Process[] myProcesses = Process.GetProcessesByName("IEXPLORE");

foreach(Process myProcess in myProcesses)
{
FindPopupToKill(myProcess);
}

protected void FindPopupToKill(Process p)
{
// traverse all threads and enum all windows attached to the thread
foreach (ProcessThread t in p.Threads)
{
int threadId = t.Id;

NativeWIN32.EnumThreadProc callbackProc =
new NativeWIN32.EnumThreadProc(MyEnumThreadWindowsProc);
NativeWIN32.EnumThreadWindows(threadId, callbackProc, IntPtr.Zero /*lParam*/);
}
}

// callback used to enumerate Windows attached to one of the threads
bool MyEnumThreadWindowsProc(IntPtr hwnd, IntPtr lParam)
{
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_CLOSE = 0xF060;


// get window caption
NativeWIN32.STRINGBUFFER sLimitedLengthWindowTitle;
NativeWIN32.GetWindowText(hwnd, out sLimitedLengthWindowTitle, 256);

String sWindowTitle = sLimitedLengthWindowTitle.szText;
if (sWindowTitle.Length==0) return true;

// find this caption in the list of banned captions
foreach (ListViewItem item in listView1.Items)
{
if ( sWindowTitle.StartsWith(item.Text) )
NativeWIN32.SendMessage(hwnd, NativeWIN32.WM_SYSCOMMAND,
NativeWIN32.SC_CLOSE,
IntPtr.Zero); // try soft kill
}

return true;
}

public class NativeWIN32
{
public delegate bool EnumThreadProc(IntPtr hwnd, IntPtr lParam);

[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern bool EnumThreadWindows(int threadId, EnumThreadProc pfnEnum, IntPtr lParam);

// used for an output LPCTSTR parameter on a method call
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct STRINGBUFFER
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
public string szText;
}

[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, out STRINGBUFFER ClassName, int nMaxCount);

[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
}

上面的方法在性能上是不错的,因为他过滤了其他非IE的窗口.但是我们可以用一个更简单的方法来实现,就是调用API FindWindowEx(HWND hWndParent, HWND hWndNext, /*in*/LPCTSTR szClassName, /*in*/LPCTSTR szWindowTitle)方法.比较有用的是这句,我们可以使用registered window class name来找到IE窗口(IEFrame是所有打开的IE的标识).

protected void FindPopupToKill()
{
IntPtr hParent = IntPtr.Zero;
IntPtr hNext = IntPtr.Zero;
String sClassNameFilter = "IEFrame"; // 所有IE窗口的类
do
{
hNext = NativeWIN32.FindWindowEx(hParent,hNext,sClassNameFilter,IntPtr.Zero);

// we've got a hwnd to play with
if ( !hNext.Equals(IntPtr.Zero) )
{
// get window caption
NativeWIN32.STRINGBUFFER sLimitedLengthWindowTitle;
NativeWIN32.GetWindowText(hNext, out sLimitedLengthWindowTitle, 256);

String sWindowTitle = sLimitedLengthWindowTitle.szText;
if (sWindowTitle.Length>0)
{
// find this caption in the list of banned captions
foreach (ListViewItem item in listView1.Items)
{
if ( sWindowTitle.StartsWith(item.Text) )
NativeWIN32.SendMessage(hNext, NativeWIN32.WM_SYSCOMMAND,
NativeWIN32.SC_CLOSE,
IntPtr.Zero); // try soft kill
}
}
}
}
while (!hNext.Equals(IntPtr.Zero));

}

public class NativeWIN32
{
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr FindWindowEx(IntPtr parent /*HWND*/,
IntPtr next /*HWND*/,
string sClassName,
IntPtr sWindowTitle);

}

代码下载:

  演示程序:

注册系统热键

  系统热键用在像弹出窗口杀手这种应用程序非常有用, Ctrl+Shift+J是缺省热键。

  说道实现,我们继续用RegisterHotkey(HWND hWnd, int id, UINT fsModifiers, UINT vkey)。完成,代码如下:

public void SetHotKey(Keys c, bool bCtrl, bool bShift, bool bAlt, bool bWindows)
{
m_hotkey = c;
m_ctrlhotkey = bCtrl;
m_shifthotkey = bShift;
m_althotkey = bAlt;
m_winhotkey = bWindows;

// update hotkey
NativeWIN32.KeyModifiers modifiers = NativeWIN32.KeyModifiers.None;
if (m_ctrlhotkey)
modifiers |= NativeWIN32.KeyModifiers.Control;
if (m_shifthotkey)
modifiers |= NativeWIN32.KeyModifiers.Shift;
if (m_althotkey)
modifiers |= NativeWIN32.KeyModifiers.Alt;
if (m_winhotkey)
modifiers |= NativeWIN32.KeyModifiers.Windows;

NativeWIN32.RegisterHotKey(Handle, 100, modifiers, m_hotkey); //Keys.J);
}
一般的,注册热键要一下几步

/* ------- using HOTKEYs in a C# application -------

-- code snippet by James J Thompson --

在Form的load 中 : Ctrl+Shift+J

bool success = RegisterHotKey(Handle,
100,
KeyModifiers.Control | KeyModifiers.Shift,
Keys.J);

在 form的closing中 :

  UnregisterHotKey(Handle, 100);

  如何处理热键 :

protected override void WndProc( ref Message m )
{
const int WM_HOTKEY = 0x0312;

switch(m.Msg)
{
case WM_HOTKEY:

MessageBox.Show("Hotkey pressed");

ProcessHotkey();

break;
}
base.WndProc(ref m );
}


public class NativeWIN32
{
[DllImport("user32.dll", SetLastError=true)]
public static extern bool RegisterHotKey( IntPtr hWnd, // handle to window
int id, // hot key identifier
KeyModifiers fsModifiers, // key-modifier options
Keys vk // virtual-key code
);

[DllImport("user32.dll", SetLastError=true)]
public static extern bool UnregisterHotKey( IntPtr hWnd, // handle to window
int id // hot key identifier
);

[Flags()]
public enum KeyModifiers
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
Windows = 8
}

}
------- using HOTKEYs in a C# application ------- */

当我们按下热键以后,流程是这样:首先用HWND GetForegroundWindow()来得到窗体,然后要抓出窗体的标题, GetWindowText(HWND hwnd, /*out*/LPTSTR lpString, int nMaxCount). 具体如下:

protected void ProcessHotkey()
{
IntPtr hwnd = NativeWIN32.GetForegroundWindow();
if (!hwnd.Equals(IntPtr.Zero))
{
NativeWIN32.STRINGBUFFER sWindowTitle;
NativeWIN32.GetWindowText(hwnd, out sWindowTitle, 256);

if (sWindowTitle.szText.Length>0)
AddWindowTitle( sWindowTitle.szText ); // add to the ListView (Form)
}
}

代码下载:

  演示程序:

转载于:https://www.cnblogs.com/leeon/archive/2005/04/15/138477.html

相关文章:

在Vue的webpack中结合runder函数

在Vue的webpack中结合runder函数 1.引入: <h1>下面是vue的内容:</h1><div id"app"><login></login> </div>2.main.js //默认无法打包vue文件 需安装vue-loader import Vue from vue import login from ./login.vuevar vm new…

CSS之定位(元素的层级z-index)

元素的层级z-index: <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>绝对定位元素的布局</title><style>.box1{width: 500px;height: 500px;background-color: #7FFFD4;position: relative;}.box2{width: 100…

忍不住要发感慨,我的这个罗技鼠真好用...

终于忍不住了&#xff0c;把台式机上的罗技鼠换到了本本上&#xff0c;我这个当初花了100元买的罗技鼠真的是好用&#xff0c;至少对我而言如是。总感觉我的那个极动鲨有些厚重&#xff0c;虽然他也一样好用&#xff0c;但同这个罗技鼠相比&#xff0c;却多了分厚重&#xff0c…

五种常用的JavaScript自定义对象方式

一、直接创建方式&#xff1a; 例子&#xff1a; var student new Object(); student.name"Kate"; student.doSprot function(name){console.log(name"正在跑步。。。") } //调用 console.log(student.name); student.doSprot("小红"); conso…

LabelButtonScale

top.geometry()设定窗口的初始大小 scale.set()设定滑块的初始值 scale.get()获取滑块变化的值 控件通过回调函数与其他控件进行通信&#xff08;Label控件中的文本会受到Scale控件上操作的影响&#xff09; 转载于:https://www.cnblogs.com/TmHm/p/9949947.html

《The Sixth Sense》(《灵异第六感》)观后

记得在学校的时候看过一部片子《左眼看到鬼》&#xff0c;现在想想那部片子有抄袭《Tht Sixth Sense》的嫌疑。不过抄袭也差得远。 现在真的懒得看港台片了&#xff0c;国内的农村&#xff0c;山村题材的都比港台的垃圾片好很多,至少还有几分真。 看了《The Sixth Sense》不得不…

mysql基本命令行

连接登录数据库 mysql -h 127.0.0.1 -P 3306 -u root -p123456 查看数据库 mysql> show databases; 进入数据库test mysql> use test; 查看test数据库中所有表 mysql> show tables; 查看表student的创建语言 mysql> show create table student \g; 查看表student的…

【备忘1】防止表格/层 被撑破的CSS控制代码

①防止表格被宽度过大的图片撑破限制大图片显示尺寸img {max-width: 550px; width:expression(this.width > 550 ? "550px" : this.width)}②防止表格被字符撑破做到既防止表格/层撑破又防止单词断裂了table {table-layout: fixed;word-wrap:break-word;}div {wo…

修改ecshop的100种技巧

1: 如何修改网站 " 欢迎光临本店 " 回答 :languages/zh_cn/common.PHP 文件中&#xff0c; $_LANG[welcome] 欢迎光临本店 ; 将他修改成你需要的字样。 2: 如何修改首页 " 热门搜索关键字 " 回答 : 后台 -> 系统设置 -> 网店设置 -> 显示设置 -…

用js 判断datagrid 中的 checkbox 是否被选中

privatevoidPage_Load(objectsender, System.EventArgs e) { // 在此处放置用户代码以初始化页面 this.sqlDataAdapter1.Fill (this.dataSet11 ); this.DataGrid1.DataSourcethis.dataSet11.Tables[0]; this.DataGrid1 .…

Navicat新建查询快捷键

在Navicat中&#xff0c;我们选中一个表&#xff0c;双击打开&#xff0c;这是如果要新建查询这个表的sql语句&#xff0c;可以直接用快捷键 ctrlq 会自动打开查询窗口&#xff0c;并直接写好 sql&#xff1a;select * from &#xff08;当前打开的表名&#xff09; 我们直接…

用JavaScript实现在网页中显示时间表

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>内置对象</title><style>#time{display: block;font-size: 50px;font-family: "微软雅黑";background-color: antiquewhite;text-align: center;}<…

分布式数据库概述

1&#xff0e;前言 随着传统的数据库技术日趋成熟、计算机网络技术的飞速发展和应用范围的扩充&#xff0c;数据库应用已经普遍建立于计算机网络之上。这时集中式数据库系统表现出它的不足&#xff1a;数据按实际需要已在网络上分布存储&#xff0c;再采用集中式处理&am…

JavaScript中substr()和substring的区别

例子&#xff1a; var letters "abcdefg"; console.log(letters.substr(1,3))//结果为bcd console.log(letters.substring(1,3));//结果为bc区别&#xff1a; substr(start,length)是从起始索引号开始提取指定长度的字符串&#xff1b;substring(start,stop)是提取…

vc++学习篇(三)——预处理命令之条件编译(#ifdef,#else,#endif,#if等)

预处理就是在进行编译的第一遍词法扫描和语法分析之前所作的工作。说白了&#xff0c;就是对源文件进行编译前&#xff0c;先对预处理部分进行处理&#xff0c;然后对处理后的代码进行编译。这样做的好处是&#xff0c;经过处理后的代码&#xff0c;将会变的很精短。 关于预处…

Tech.Ed2005 讲义下载地址

前天刚刚下载了微软技术大会 Tech.Ed2005 讲义全文&#xff0c;我打了包&#xff0c;供大家下载 下载地址&#xff1a;Tech.Ed2005 讲义下载

Educational Codeforces Round 54

这套题不难&#xff0c;但是场上数据水&#xff0c;导致有很多叉点 A. 因为是让求删掉一个后字典序最小&#xff0c;那么当a[i]>a[i1]的时候&#xff0c;删掉a[i]一定最优&#xff01;这个题有个叉点&#xff0c;当扫完一遍如果没有满足条件的&#xff0c;就删去最后一个字符…

武夷游记(二)

在竹筏漂流九曲溪之前导游就告诫我们&#xff1a;要给艄公小费&#xff0c;才能划得慢而且讲得多。但同船渡的都是年轻人&#xff0c;不明就理的我们不知道什么时候给。果不其然&#xff0c;一路上船划得飞快&#xff0c;势如强弩&#xff0c;连超了好几艘竹排&#xff0c;要是…

【bzoj3261】最大异或和 可持久化Trie树

题目描述 给定一个非负整数序列 {a}&#xff0c;初始长度为 N。 有M个操作&#xff0c;有以下两种操作类型&#xff1a;1、A x&#xff1a;添加操作&#xff0c;表示在序列末尾添加一个数 x&#xff0c;序列的长度 N1。2、Q l r x&#xff1a;询问操作&#xff0c;你需要…

如何给HTML添加事件?

第一种方式&#xff1a; 直接在相应的HTML标签中添加相应的属性&#xff0c;通过属性去添加事件。 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>HTML添加事件的方式&#xff08;一&#xff09;</title><scri…

Case When 解决简单的是与否

昨天晚上买了一个sql的新书&#xff0c;特别的高兴&#xff0c;晚上就阅读了很多&#xff0c;突然发现以前经常在SQL中使用的case when的用法&#xff0c;以前在csdn上面看到好多&#xff0c;但是就是不知道怎么用&#xff0c;可能那个时候还没有用到的地方&#xff0c;不过现在…

Vue异步组件Demo

Vue异步组件Demo 在大型应用中&#xff0c;我们可能需要将应用拆分为多个小模块&#xff0c;按需从服务器下载。为了进一步简化&#xff0c;Vue.js 允许将组件定义为一个工厂函数&#xff0c;异步地解析组件的定义。Vue.js 只在组件需要渲染时触发工厂函数&#xff0c;并且把结…

JS笔记(一):声明提升

我们习惯将 var a 2; 看作一个声明&#xff0c;而实际上JavaScript引擎并不这么认为。他将 var a 和 a 2 当作两个单独的声明&#xff0c;第一个是编译阶段的任务&#xff0c;第二个则是执行阶段的任务。 ——《你不知道的Js》 变量提升 变量提升的概念已经为大家所熟知&…

event对象(触发机制)

Event 对象代表事件的状态&#xff0c;比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态&#xff0c;常用事件如下&#xff1a; 事件触发时机onchange用户改变域的内容onclick鼠标点击某个对象onfocus、onblur元素获得焦点、失去焦点时触发onkeydown、o…

3种方式理解旋转变换

有V1(x1,y1), 求这个点绕坐标原点旋转θ角度后的坐标V2(x2,y2) 1.三角函数 假设(x1,y1)(Rcosα,Rsinα) (x2,y2) (Rcos(αθ),Rsin(αθ)) (Rcosαcosθ-Rsinαsinθ,RcosαsinθRsinαcosθ) (x1cosθ-y1sinθ,x1sinθy1cosθ) 2.坐标轴旋转 如果有向量Ax&#xff1d…

Yahoo中国变脸?

今天看到一则消息“门户雅虎走了”&#xff0c;到Yahoo中国网站一看&#xff0c;果然首页变成简洁的以搜索为主的页面。原来的Yahoo首页成为现在的“资讯首页”。似乎Yahoo中国要在搜索上大干一场……

ubuntu14.04上搭建android开发环境

这几天心血来潮&#xff0c;想在ubuntu上写写android软件。所以就上网找些资料在ubuntu上搭建android环境。结果要么时不完整的&#xff0c;要么就是过时的。所以我把我搭建android环境的过程写下了&#xff0c;以便以后忘了能够參考參考&#xff0c;也给来看这篇博文的读者一些…

nuxt.js实战之移动端rem

nuxt.js的项目由于是服务端渲染&#xff0c;通过js动态调整不同尺寸设备的根字体这种rem方案存在一种缺陷。由于设置字体的代码不能做服务端渲染&#xff0c;导致服务端返回的代码一开始没有相应的跟字体&#xff0c;直到与前端代码进行合并根字体改变&#xff0c;这就造成我们…

Window对象中setInterval()和setTimeout()的区别

- setInterval("",time)&#xff1a;每隔指定的时间执行一次调用的函数或计算表达式&#xff0c;如果不停止会无限次去执行&#xff1b; - setTimeout("",time)&#xff1a;在指定时间的最后执行一次调用的函数或计算表达式&#xff0c;仅执行一次。 <…

妹妹生了个女儿,纪念一下

下午艺花打电话告诉我&#xff0c;春兰生了个女儿。 赶紧发了短信过去询问情况&#xff0c;没想到妹夫就打了电话过来&#xff0c;换了她上线&#xff0c;声音里透着初为人母的喜悦&#xff0c;很为她高兴。她说生产不是很顺利&#xff0c;后来剖腹才产下了小外甥女&#xff0c…