B3log Solo  当前在线人数:12 登录 注册

奔放的胸毛。

天行健 胸毛以自强不息

DIV + CSS 教程(一)——前言

2011-01-25 12:28:58 奔放的胸毛。
0  评论    8,056  浏览

CSS

决心写点东西了,一为归纳总结自己所学,查漏补缺,二来也可以帮助一些人。做程序员时间不长,会的东西也不多,所以语言方面就不敢拿出来讲了。看到国内Table布局盛行,做出来的页面惨不忍睹(至少是代码惨不忍睹),所以选择写一套关于CSS的东西。

这几天在看汇编,里面的教学风格我很喜欢。所以我准备用那种传授知识的思想来写这一套博文。首先,这一套东西旨在教会读者如何使用DIV + CSS,而不仅仅只是我的技术的全面展示。我认为,将技术点全部列出来那不能算是教程,那是帮助文档。所以我写的不是一套CSS查询手册,而是用尽量少的知识告诉读者如何使用CSS。是的,尽量少的知识!

我的宗旨是,能不讲的先不讲,讲多了容易一个都记不住。一大锅放在脑子里,总觉得什么都会,却又不能通透。所以我每一个阶段只讲一点点,学完之后读者能够很清晰的知道脑子里有些什么,它们是什么样子的,干净利落而不是浆糊。

当你准备跟进这一套教程之前你应该已经具备以下条件:

  1. 有通过学习从而提高自我的欲望
  2. 已经熟悉HTML标签

在讲解中会有一些阶段性的小实验和练习题。解决它们,必须要解决它们。如果没有通过当前阶段的小实验或者练习题,请不要继续后面的学习。这是对自己负责,坚决不造成脑子里一大锅理不清道不明的情况。将每一块弄通透。

,

神曲《忐忑·龚琳娜》

2011-01-21 22:03:17 奔放的胸毛。
1  评论    6,192  浏览

这首歌表达了一只公鸡将要生蛋时迷惑,抑郁,痛苦,迷茫,蛋疼而又兴奋的纠结心情
——某网友这样评论道



ASCALL码表

2011-01-18 21:31:45 奔放的胸毛。
0  评论    38,097  浏览

  • 二进制十进制十六进制缩写解释
  • 0000 0000000NUL空字符(Null)
  • 0000 0001101SOH标题开始
  • 0000 0010202STX正文开始
  • 0000 0011303ETX正文结束
  • 0000 0100404EOT传输结束
  • 0000 0101505ENQ请求
  • 0000 0110606ACK收到通知
  • 0000 0111707BEL响铃
  • 0000 1000808BS退格
  • 0000 1001909HT水平制表符
  • 0000 1010100ALF换行键
  • 0000 1011110BVT垂直制表符
  • 0000 1100120CFF换页键
  • 0000 1101130DCR回车键
  • 0000 1110140ESO不用切换
  • 0000 1111150FSI启用切换
  • 0001 00001610DLE数据链路转义
  • 0001 00011711DC1设备控制1
  • 0001 00101812DC2设备控制2
  • 0001 00111913DC3设备控制3
  • 0001 01002014DC4设备控制4
  • 0001 01012115NAK拒绝接收
  • 0001 01102216SYN同步空闲
  • 0001 01112317ETB传输块结束
  • 0001 10002418CAN取消
  • 0001 10012519EM介质中断
  • 0001 1010261ASUB替补
  • 0001 1011271BESC溢出
  • 0001 1100281CFS文件分割符
  • 0001 1101291DGS分组符
  • 0001 1110301ERS记录分离符
  • 0001 1111311FUS单元分隔符
  • 0111 11111277FDEL删除
奔放的胸毛。
lyzane.it@gmail.com
,

Winform操作注册表,锁屏小工具的拓展(三)

2010-08-17 13:34:00 奔放的胸毛。
0  评论    5,812  浏览

在上一章中我们已经完成了对密码的加密,然后今天我们将把我们加密后的密码储存在注册表中,并且能修改。也就是对注册表的增删改查。

注册表概述

首先介绍下Windows操作系统中的注册表是什么?有什么作用?。

很早以前的注册表咱就不管了,只说说目前主流的几个Windows操作系统中的注册表。按照我个人的理解,注册表在操作系统中的角色是一个巨大的配置文件数据库。这个特殊的“数据库”里面储存着大量的操作系统配置信息。

比如是否使用屏保、使用的屏保文件的路径、是否开启来宾用户、两次鼠标点击间隔在多少毫秒内才算双击、是否自动排列图标、按照什么顺序排列图标、鼠标的指针移动速速、使用什么连接连接到网络、是否开启系统防火墙、是否开启自动更新、“我的文档”的路径、“我的电脑”的图标路径、腾讯QQ可执行文件路径等等等等……

为什么可以把原本在C盘的“我的文档”移动到D盘,就是因为修改了注册表里标示“我的文档”的路径的键的值。

为什么有时在网页上点击类似于“QQ会话”图片的图片可以启动QQ聊天软件?网页怎么知道我的QQ安装在何处?因为每次安装QQ的时候QQ安装程序都会在注册表中添加一条记录,这个记录便是QQ的安装路径,在网页上点击图片后被执行的程序只要读取这个位置的路径便可以知道“QQ.exe”在哪,然后启动它。

这就是注册表的作用——它是操作系统中的配置信息数据库(个人通俗描述)。

所以,我们可以用这个“数据库”来储存我们锁屏工具的密码,虽然注册表所有人都可以打开看,但是估计一般人看到注册表里面的数据都会晕的,更不会去找你的密码放在哪了,更何况就算找到了它也是经过加密的。安全性方面我觉得这样已经比较可靠了,我知道世上什么高手都有,但是我觉得没有几个人会有兴趣来研究我的锁屏工具的密码的。

在命令行输入命令“regedit”打开注册表编辑器,如图:

2010-08-17_110715 2

2010-08-17_111128

根据这后两张图我们可以看到注册表是以树形结构来存储数据的,这个树的根节点叫做“我的电脑”,然后下面有5个主节点。这5个主节点下分别对应储存这些配置信息(个人描述不专业,下列介绍来自百度百科):

HKEY_CLASSES_ROOT

在注册表中HKEY_CLASSES_ROOT是系统中控制所有数据文件的项。这个在Win95和Winnt中是相通的。HKEY_CLASSES_ROOT控制键包括了所有文件扩展和所有和执行文件相关的文件。它同样也决定了当一个文件被双击时起反应的相关应用程序。

HKEY_CURRENT_USER

 

       HKEY_CURRENT_USER包含着在HKEY_USERS安全辨别里列出的同样信息。任何在HKEY_CURRENT_USER里的改动也都会立即HKEY_USERS改动。相反也是这样。

 

HKEY_CURRENT_USER允许程序员和开发者易于存取目前登陆用户的设置。通过建立这个键,微软很容易在不涉及到用户的SID下改变,添加和设置。

也就是说,所有当前的操作改变只是针对当前用户而改变,并不影响其他用户。

HKEY_CURRENT_CONFIG

win95一般只使用一个硬件配置文件。如果有多个硬件配置文件。HKEY_LOCAL_MACHINE\Config中就会添加一个键。HKEY_LOCAL_MACHINE\Config包含了HKEY_LOCAL_MACHINE中相同的数据

在启动时,你可以选择你愿意使用的配置文件。如果有多个安装,每次系统重新启动时,你就必须选择.HKEY_CURRENT_CONFIG是在启动时控制目前硬件配置的键

在系统启动以后,任何地方的变化都会自动影响到它。程序员经常使用HKEY_CURRENT_CONFIG方便的来存取配置信息。

HKEY_CURRENT_CONFIG包括了系统中现有的所有配置文件的细节。你的选择影响了哪一个硬件配置文件成为现在的。举例来说,如果配置0002被选择了,所有0002的配置信息会被映射到这些键上

HKEY_CURRENT_CONFIG允许软件和设备驱动程序员很方便的更新注册表,而不涉及到多个配置文件信息。 HKEY_LOCAL_MACHINE中同样的数据和任何注册表的变化都会同时的变化。

HKEY_USERS

HKEY_USERS将缺省用户和目前登陆用户的信息输入到注册表编辑器,在win95中,它仅被那些配置文件激活的登陆用户使用,同样在nt下,它也是这样。

win95从user.dat中取得他们的信息,winnt从ntuser.dat中取得信息。.dat文件包含了所有基于用户的注册表设置并且允许你取配置这些用户的环境。如果你改变了缺省用户的设置,所有新用户会继承同样的设置。而且,那些已经被建立的用户变的失效。

HKEY_LOCAL_MACHINE

HKEY_LOCAL_MACHINE是一个显示控制系统和软件的处理键。HKLM键保存着计算机的系统信息。它包括网络和硬件上所有的软件设置。(比如文件的位置,注册和未注册的状态,版本号等等)这些设置和用户无关,因为这些设置是针对使用这个系统的所有用户的。

HKEY_LOCAL_MACHINE节点是我们今天的重点,软件设置信息一般都存放在这里,为什么存放在这个节点下而不存放在其它地方呢?我们把信息藏在一个很少有人知道的地方岂不更加安全么?这是因为,注册表中的每个节点都有权限分配,当然,我们以Administrators的身份进入系统那绝对是哪都能操作的,但是,并不是所有的人都是以管理员的身份进入的系统,所以并不是所有的当前用户都对注册表的所有节点有操作权限。

所以,微软当初在做这个操作系统的时候就安排好了,HKEY_LOCAL_MACHINE节点下的SOFTWARE节点用于各种软件存储信息。

2010-08-17_114355

如何称呼注册表中的各“部件”:

2010-08-17_113255

项:左半边带有文件夹图标的节点全部都称为项。

键:右半边里面的一行数据就是一个键。

键的名称:如图。

键的类型:最前面说道,注册表是一个“配置信息数据库”,既然是“数据库”,那么,很显然“数据库”是不光能够存储字符串类型数据的。能储存什么数据看图:

2010-08-17_115526

我们今天的需求只需要存储字符串类型的数据,所以其它的就不管了。

键的数据:如图。

分析需求并编程实现

说到底,今天我们的需求就是要在注册表中储存锁屏工具的密码,然后实现登陆验证和修改密码的功能。

经过前面对注册表的分析,我们需要在HKEY_LOCAL_MACHINE\SOFTWARE下建立一个自定义项,然后在我们建立的项中插入一个字符串类型的键,并在建中储存我们的密码。

操作注册表引用命名空间:using Microsoft.Win32;

编程思路及代码

· 增

由于注册表中没有专门给锁屏工具存东西的地方,所以,我们每次打开锁屏工具的时候就要看看注册表中的HKEY_LOCAL_MACHINE\SOFTWARE下建立了锁屏工具的数据项和键没有,如果已经建立了,不管。如果没有建立,说明这是第一次运行锁屏工具,在HKEY_LOCAL_MACHINE\SOFTWARE下建立一个名为“Zane”(这是我自己随便起的名字)的项,然后在这个项下面建个字符串类型名为“zane”,值为DESEncrypt.Encrypt("")的键(DESEncrypt类中的Encrypt方法为加密方法,将空字符串加密后再放在注册表安全性更高),这个键的值就是我们第一次使用锁屏工具的默认密码。

关键代码,在Load时调用RegedieValidate()即可(注册表中的路径不分大小写):

        /// 
        /// 检查注册表中是否已经存在Zane项和zane键,如果没有,创建
        /// 
        private void RegedieValidate()
        {
            if (!IsRegeditItemExist())//首先判断是否存在Zane项,没有就建立
            {
                RegistryKey key = Registry.LocalMachine;//获取HKEY_LOCAL_MACHINE节点
                key.CreateSubKey("software\\Zane");//建立该节点,如果该节点已经存在,则不影响
            }
            if (!IsRegeditKeyExit())//然后判断Zane项中是否有zane键,没有就添加默认密码记录
            {
                RegistryKey key = Registry.LocalMachine;
                RegistryKey software = key.OpenSubKey("software\\Zane", true);  //该项必须已存在
                software.SetValue("zane", DESEncrypt.Encrypt(" "));
            }
        }

        /// 
        /// 判断是否存在Zane节点
        /// 
        /// 
        private bool IsRegeditItemExist()
        {
            string[] subkeyNames;
            RegistryKey hkml = Registry.LocalMachine;
            RegistryKey software = hkml.OpenSubKey("SOFTWARE");
            //RegistryKey software = hkml.OpenSubKey("SOFTWARE", true);  
            subkeyNames = software.GetSubKeyNames();
            //取得该项下所有子项的名称的序列,并传递给预定的数组中  
            foreach (string keyName in subkeyNames)   //遍历整个数组  
            {
                if (keyName == "Zane") //判断子项的名称  
                {
                    hkml.Close();
                    return true;
                }
            }
            hkml.Close();
            return false;
        }

        /// 
        /// 判断密码是否存在(判断是否存在zane键)
        /// 
        /// 
        private bool IsRegeditKeyExit()
        {
            string[] subkeyNames;
            RegistryKey hkml = Registry.LocalMachine;
            RegistryKey software = hkml.OpenSubKey("SOFTWARE\\Zane");
            subkeyNames = software.GetValueNames();
            //取得该项下所有键值的名称的序列,并传递给预定的数组中   
            foreach (string keyName in subkeyNames)
            {
                if (keyName == "zane")    //判断键值的名称   
                {
                    hkml.Close();
                    return true;
                }
            }
            hkml.Close();
            return false;
        }

· 查

这样一来,HKEY_LOCAL_MACHINE\SOFTWARE\Zane下的zane键就是我们储存密码的地方了。

密码储存在这里之后每次解锁就在这里取得密码,然后进行登录验证。

取得HKEY_LOCAL_MACHINE\SOFTWARE\Zane下的zane键的值,并进行登录验证的代码如下:

/// 
/// 密码验证
/// 
/// 
private bool PwdValidate()
{
    RegistryKey Key = Registry.LocalMachine;
    RegistryKey Zane = Key.OpenSubKey("software\\Zane", true);
    string pwd = Zane.GetValue("zane").ToString();
    Zane.Close();
    if (DESEncrypt.Encrypt(txtPassword.Text) != pwd)
    {
        count++;
        lblMsg.Text = "密码错误";
        if (count >= 4)
        {
            lblMsg.Text = "警告:\r\n你猥琐的面孔已被摄像头捕获\r\n并发送到主人邮箱中";
        }
        lblMsg.Visible = true;
        txtPassword.SelectAll();
        return false;
    }
    count = 0;
    txtPassword.Text = " ";
    return true;
}

上面的代码里面包含一些用于提示信息的label的控制,至于用摄像头捕捉猥琐人物的照片,并将照片发送到指定邮箱的功能在后续章节中添加。

· 改

有密码的地方就会有登录验证和修改密码。

private void btnOK_Click(object sender, EventArgs e)
{
    if (txtNew.Text.Trim() == " ")
    {
        MessageBox.Show("新密码不能为空!");
        return;
    }
    if (txtNew.Text != txtReset.Text)
    {
        MessageBox.Show("两次输入的密码不一致!");
        return;
    }
    RegistryKey Key = Registry.LocalMachine;
    RegistryKey Zane = Key.OpenSubKey("software\\Zane",true);
    string pwd = Zane.GetValue("zane").ToString();
    if (DESEncrypt.Encrypt(txtOld.Text) != pwd)
    {
        MessageBox.Show("密码错误!");
        return;
    }
    Zane.SetValue("zane", DESEncrypt.Encrypt(txtNew.Text));
    Zane.Close();
    this.Close();//修改成功后关闭本Form
}

· 删

虽然锁屏工具不需要删除注册表中的记录,但是我还是一并把删除注册表中的记录的代码贴出来,这是遍历清空某项的键的代码:

private void DeleteRegist(string name) 
{ 
   string[] keys; 
   RegistryKey hkml = Registry.LocalMachine; 
   RegistryKey software = hkml.OpenSubKey("SOFTWARE",true); 
   RegistryKey Zane = software.OpenSubKey("Zane",true); 
   keys = Zane.GetSubKeyNames(); 
   foreach(string key in keys) 
   { 
    if(key == name) 
     Zane.DeleteSubKeyTree(name); 
   } 
}

直接删除某项的代码就不贴了,只需要调用父节点的DeleteSubKey("子项的name");就可以删除叫name的子项了,当然,也包括子项中所有的键。

到此为止,一个完整的锁屏工具就完成了,不过我准备给这个锁屏工具添加更过的细节功能,使之更强大。当然,学习各种各样的技术手段才是重点。

,

Winform 字符串加密/解密,锁屏小工具的拓展(二)

2010-08-13 16:38:00 奔放的胸毛。
1  评论    8,812  浏览

这是我的舞台,虽然我很草根,写的东西没什么技术含量,也没有人鼓掌,但是有人看,这就足够了。

大家好才是真的好,我将一如既往的曝光我的草根Code。

上次我们完成了锁屏工具的雏形,但是没有实现用户自定义密码。今天将实现密码的加密与解密,为后面把密码保存在注册表中做准备。

我所使用的字符串加密方法并不是我写的,也不是很火的MD5等加密方法,仅仅是用.net中现有的类来处理字符串,实现加密的过程。先看代码,再讲解使用方法:

using System;
using System.Security.Cryptography;
using System.Text;
namespace LockScreen
{
	/// <summary>
	/// DES加密/解密类。
	/// </summary>
	public class DESEncrypt
	{
		public DESEncrypt()
		{			
		}

		#region ========加密======== 
 
        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="Text"></param>
        /// <returns></returns>
		public static string Encrypt(string Text) 
		{
			return Encrypt(Text,"zane");
		}
		/// <summary> 
		/// 加密数据 
		/// </summary> 
		/// <param name="Text"></param> 
		/// <param name="sKey"></param> 
		/// <returns></returns> 
		public static string Encrypt(string Text,string sKey) 
		{
			DESCryptoServiceProvider des = new DESCryptoServiceProvider(); 
			byte[] inputByteArray; 
			inputByteArray=Encoding.Default.GetBytes(Text); 
			des.Key = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey, "md5").Substring(0, 8)); 
			des.IV = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey, "md5").Substring(0, 8)); 
			System.IO.MemoryStream ms=new System.IO.MemoryStream(); 
			CryptoStream cs=new CryptoStream(ms,des.CreateEncryptor(),CryptoStreamMode.Write); 
			cs.Write(inputByteArray,0,inputByteArray.Length); 
			cs.FlushFinalBlock(); 
			StringBuilder ret=new StringBuilder(); 
			foreach( byte b in ms.ToArray()) 
			{ 
				ret.AppendFormat("{0:X2}",b); 
			} 
			return ret.ToString(); 
		} 

		#endregion
		
		#region ========解密======== 
   
 
        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="Text"></param>
        /// <returns></returns>
		public static string Decrypt(string Text) 
		{
            return Decrypt(Text, "zane");
		}
		/// <summary> 
		/// 解密数据 
		/// </summary> 
		/// <param name="Text"></param> 
		/// <param name="sKey"></param> 
		/// <returns></returns> 
		public static string Decrypt(string Text,string sKey) 
		{ 
			DESCryptoServiceProvider des = new DESCryptoServiceProvider(); 
			int len; 
			len=Text.Length/2; 
			byte[] inputByteArray = new byte[len]; 
			int x,i; 
			for(x=0;x<len;x++) 
			{ 
				i = Convert.ToInt32(Text.Substring(x * 2, 2), 16); 
				inputByteArray[x]=(byte)i; 
			} 
			des.Key = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey, "md5").Substring(0, 8)); 
			des.IV = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey, "md5").Substring(0, 8)); 
			System.IO.MemoryStream ms=new System.IO.MemoryStream(); 
			CryptoStream cs=new CryptoStream(ms,des.CreateDecryptor(),CryptoStreamMode.Write); 
			cs.Write(inputByteArray,0,inputByteArray.Length); 
			cs.FlushFinalBlock(); 
			return Encoding.Default.GetString(ms.ToArray()); 
		} 
 
		#endregion 


	}
}

加密和解密方法都有+2重载,因为这个算法中需要两个加密/解密“种子”,这两个种子用于参与加密/解密的运算过程,种子不同,加密/解密的结果也就不一样,所以就算别人知道你的算法,但是不知道你的种子参数,还是不能进行解密(我说的不能解密是狭义的,别老拿FBI级别的队伍说事)。

System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey, "md5"),这里有两个参数,这两个参数就是刚刚提到的加密/解密种子,为求简单,方法中只把第一个种子作为参数作为调用时输入,第二个参数直接写死,为“MD5”。虽然这里写了个md5,顺便也通过一个我们公司的笑话说说md5加密。

某天,BOSS不知道在哪搞到了md5加密的源码,然后召集队伍,下达了命令,要求一个星期之内研究出md5解密。因为BOSS知道:md5加密是让数据的每一个0和1参与运算,加密结果为一个长度为32的字符串。由于是让每一个字节都参与了运算,所以加密的结果跟每一个字节都有关。既然加密后的结果跟加密前的每个字节都有关,那么肯定能根据加密的结果反推出加密前的数据。

忽然间老板雄起了,因为一旦实现md5解密,那么就能根据一个长度为32的字符串反推出加密前的数据,加密前的数据,它可能是一部20G的高清大片。这个意义就非比寻常了,那将是世界上最先进的压缩技术——再大的数据也能压成32长度的字符串。解压即解密。

如果在U盘里面内置一个md5加解密程序,一个U盘的容量将达到理论上的无限大…BOSS越想越兴奋。

但是当我们告诉他不可能实现的时候老板显得很不解:“源代码都给你们了,这都搞不定!这么简单的事情!点一下就OK了嘛!……”。

事情最终不了了之,讲到这里也说明md5加密是不可逆的,是不能解密的,它是一种有损加密。也就是加密后的数据比加密前要少。上面贴出来的加密算法是可以被解密的,它加密后的数据比加密前要多,属于无损加密。

今天就写到这里了,明天我们将会把加密后的密码储存在注册表中,同时讲解注册表的“增删改查”。

,

Winform 键盘钩子,锁屏小工具的实现(一)

2010-08-12 10:48:00 奔放的胸毛。
0  评论    6,863  浏览

闲来无聊,给自己做了个锁屏小工具,在这里写写步骤,感兴趣的看看。

新建Windws工程后将Form1的FormBorderStyle设置为None,使这个窗口没有边框;TopMost为True,使这个窗口始终在所有窗口的最上方;设置WindowState为Maximized,使窗口一开始就是最大化状态;设置ShowInTaskbar为False,使窗口不在任务栏出现。

然后给窗体设置一张自己喜欢的背景图片,再把BackGroundImageLayout设置为None,使背景图片不重复。

然后在窗口左下角放置一个密码框和一个按钮,按钮单击事件里面暂定密码为“123”就可以退出锁屏。

现在按下Ctrl + F5启动程序,初步效果就已经出来了。

但是这个时候按下Alt + F4就可以关闭锁屏工具,没有安全性可言,所以我们要使用键盘钩子来阻止这一行为。键盘钩子的原理就是通过Windows API实现我们的程序可以获取到所有的键盘事件,只要键盘稍有“响动”,锁屏工具就会第一时间获取到这一信息,然后我们就可以把这一信息拦截,拦截之后不告诉操作系统有按键事件发生,操作系统就不会做出反应。

但是由于我们需要用键盘输入密码来解锁,所以我们不能屏蔽所有的按键,我们也不需要屏蔽所有的按键,只需要把Ctrl、Alt、Win、Tab等功能键屏蔽掉就够了,没了这些功能键,就不能用键盘关闭锁屏工具了。

到底屏蔽哪些键,在下面这个类中的方法KeyboardHookProc中可以自行添加修改。

安装钩子:InstallHook()、卸载钩子:UnInstallHook()。

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using System.Reflection;
using System.Windows.Forms;

namespace LockScreen
{
    public class Hook_Keyboard
    {
        #region 私有变量

        /// <summary>
        /// 键盘钩子句柄
        /// </summary>
        private IntPtr m_pKeyboardHook = IntPtr.Zero;

        /// <summary>
        /// 钩子委托声明
        /// </summary>
        /// <param name="nCode"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);

        /// <summary>
        /// 键盘钩子委托实例
        /// </summary>
        /// <remarks>
        /// 不要试图省略此变量,否则将会导致
        /// 激活 CallbackOnCollectedDelegate 托管调试助手 (MDA)。 
        /// 详细请参见MSDN中关于 CallbackOnCollectedDelegate 的描述
        /// </remarks>
        private HookProc m_KeyboardHookProcedure;

        // 底层键盘钩子
        public const int idHook = 13;

        /// <summary>
        /// 安装钩子
        /// </summary>
        /// <param name="idHook"></param>
        /// <param name="lpfn"></param>
        /// <param name="hInstance"></param>
        /// <param name="threadId"></param>
        /// <returns></returns>
        [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn,
            IntPtr pInstance, int threadId);

        /// <summary>
        /// 卸载钩子
        /// </summary>
        /// <param name="idHook"></param>
        /// <returns></returns>
        [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern bool UnhookWindowsHookEx(IntPtr pHookHandle);

        /// <summary>
        /// 传递钩子
        /// </summary>
        /// <param name="pHookHandle">是您自己的钩子函数的句柄。用该句柄可以遍历钩子链</param>
        /// <param name="nCode">把传入的参数简单传给CallNextHookEx即可</param>
        /// <param name="wParam">把传入的参数简单传给CallNextHookEx即可</param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int CallNextHookEx(IntPtr pHookHandle, int nCode,
            Int32 wParam, IntPtr lParam);

        #endregion 私有变量

        #region 私有方法


        /// <summary>
        /// 键盘钩子处理函数
        /// </summary>
        /// <param name="nCode"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        /// <remarks>此版本的键盘事件处理不是很好,还有待修正.</remarks>
        private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            //return 1;
            KeyMSG m = (KeyMSG)Marshal.PtrToStructure(lParam, typeof(KeyMSG));
            if (m_pKeyboardHook != IntPtr.Zero)
            {
                switch (((Keys)m.vkCode))
                {
                    case Keys.LWin:
                    case Keys.RWin:
                    case Keys.Delete:
                    case Keys.Alt:
                    case Keys.Escape:
                    case Keys.F4:
                    case Keys.Control:
                    case Keys.Tab:
                        return 1;
                }
            }
            return 0;
        }

        #endregion 私有方法

        #region 公共方法

        /// <summary>
        /// 安装钩子
        /// </summary>
        /// <returns></returns>
        public bool InstallHook()
        {
            //IntPtr pInstance = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().ManifestModule);
            IntPtr pInstance = (IntPtr)4194304;
            if (this.m_pKeyboardHook == IntPtr.Zero)
            {
                this.m_KeyboardHookProcedure = new HookProc(KeyboardHookProc);
                this.m_pKeyboardHook = SetWindowsHookEx(idHook, m_KeyboardHookProcedure, pInstance, 0);
                if (this.m_pKeyboardHook == IntPtr.Zero)
                {
                    this.UnInstallHook();
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// 卸载钩子
        /// </summary>
        /// <returns></returns>
        public bool UnInstallHook()
        {
            bool result = true;
            if (this.m_pKeyboardHook != IntPtr.Zero)
            {
                result = (UnhookWindowsHookEx(this.m_pKeyboardHook) && result);
                this.m_pKeyboardHook = IntPtr.Zero;
            }
            return result;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct KeyMSG
        {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;
        }
        #endregion 公共方法
    }
}

修改我们刚刚的锁屏工具,在窗体加载的时候安装钩子,在窗体关闭ing的时候卸载钩子即可。

启动程序观察效果,果然强大了。

但是还是有问题,理论上是屏蔽了这些功能键了,但是按下Ctrl + Alt + Del的时候居然还

是可以调出系统的任务管理器,并且任务管理器的窗口Top级别是最高的,所以可以通过任务管理器

关闭锁屏工具,这个问题可以这样解决:

        /// <summary>
        /// 用Timer杀死任务管理器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer1_Tick(object sender, EventArgs e)
        {
            try
            {
                this.Activate();

                Process[] myProcess = Process.GetProcesses();
                foreach (Process p in myProcess)
                {
                    if (p.ProcessName == "taskmgr")
                    {
                        p.Kill();
                        return;
                    }
                }
            }
            catch (Exception)
            {

            }
        }

这是我在Form中添加一个Timer的Tick事件,用这个事件来“杀死”任务管理器进程就OK了。

到这里,我们的锁屏工具基本上已经刀枪不入了。锁屏之后除非有密码,别人是动不了被锁的电脑的。

    警告:卸载钩子这一步骤在程序被关闭时一定要执行,不然很麻烦,很可能出现锁屏工具已经关闭了,但是键盘还是被锁着在。然后建议在制作调试的过程中不启用Timer,以免一不小心出点小毛病输不了密码,键盘也被锁,任务管理器也打不开,那就只好重启电脑了。如果后期加了开机自启动功能,出现这毛病,重启都不顶事,哭去吧。

虽然这个锁屏工具实现是锁屏的功能,安全性也还不错,但是这个简易的锁屏工具离真正的“产品”的要求还很远,比如密码不能修改、锁屏功能不能被快捷键呼出、锁屏工具不能开机自启动等细节问题。我将在接下来的几章里继续完善。

,

Winform 将Ico图标转换为PNG图片

2010-08-11 14:26:00 奔放的胸毛。
0  评论    11,801  浏览

不管是做web,还是做C/S,经常会用到各种各样的功能按钮图片。然而有的时候控件要求图片格式为Ico,有时候要求是jpg、png、gif等。再加上网上的精美图标资源很多,图标的尺寸都比较统一等等因素,图标转化成png图片,然后拿去做按钮是非常不错的。

在网上找了半天,png转ico的工具很多,但是ico转png的却没有找到,所以就自己研究了下,做了个。其实做这个东西非常简单,代码也很少,这是全部代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace IconToBmp
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        List<string> iconList = new List<string>();
        string outPath;
        string selectPath;
        /// <summary>
        /// 选择图标
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSelect_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                iconList.Clear();
                foreach (string str in openFileDialog1.FileNames)
                {
                    iconList.Add(str);
                }
                selectPath = openFileDialog1.FileName;
                txtInput.Text = "选择了" + iconList.Count.ToString() + "个图标。";
            }
        }
        /// <summary>
        /// 选择输出文件夹
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOutput_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                outPath = folderBrowserDialog1.SelectedPath;
                txtOutput.Text = outPath;
            }
        }
        /// <summary>
        /// 转换前的数据验证
        /// </summary>
        /// <returns></returns>
        private bool Valid()
        {
            if (txtOutput.Text.Trim() == "")
            {
                MessageBox.Show("请选择图片输出位置!");
                return false;
            }
            if (iconList.Count == 0 || iconList == null)
            {
                MessageBox.Show("请选择要转化的图标!");
                return false;
            }
            return true;
        }
        /// <summary>
        /// 转换
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnGo_Click(object sender, EventArgs e)
        {
            if (!Valid())
            {
                return;
            }
            int count = 0;
            foreach (string str in iconList)
            {
                try
                {
                    string iconName = str.Substring(str.LastIndexOf(@"\")).Replace(".ico", ".png");
                    System.Drawing.Icon icon = new Icon(str);
                    Bitmap bmp = icon.ToBitmap();
                    if (File.Exists(@outPath + iconName))//如果该文件已经存在
                    {
                        DialogResult result = MessageBox.Show(iconName.Substring(1) + "已存在,是否替换?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
                        if (result == DialogResult.OK )//如果替换
                        {
                            bmp.Save(@outPath + iconName);
                            count++;
                        }
                    }
                    else
                    {
                        bmp.Save(@outPath + iconName);
                        count++;
                    }
                    
                }
                catch (Exception ex)
                {
                    MessageBox.Show("遇到异常,已终止转换,已转换"+count.ToString()+"个文件,异常消息:"+ex.Message);
                    return;
                }
            }
            MessageBox.Show("共选择"+iconList.Count+"个图标,已转换" + count.ToString() + "个,"+(iconList.Count-count).ToString()+"个被跳过。");
        }

        /// <summary>
        /// 窗体加载
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e)
        {
            folderBrowserDialog1.RootFolder = Environment.SpecialFolder.Desktop;
            if (selectPath != "")
            {
                openFileDialog1.InitialDirectory = selectPath;
            }
        }
    }
}
,

窗体镂空效果以及无标题栏窗体鼠标拖动效果的实现

2010-08-11 13:38:00 奔放的胸毛。
0  评论    11,598  浏览

最开始我以为要用Win API,然后发送消息等等才能实现,最后搞来搞去才发现,其实很简单,不需要Win API,也不需要发送消息,也不需要第三方控件,也不需要添加控件。

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace HollowOutDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        /*
         * 作者:“奔放的胸毛。”(lyzane.it@gmail.c)
         * Demo功能简介,及实现思路:
         * ①:实现了镂空窗体的效果
         * 首先设置窗体背景色为Yellow,然后将窗体TransparencyKey属性(绘制到窗体上时,显示为透明的颜色)也设置为Yellow
         * 这样一来,整个窗体就全部透明了,然后我找了张PNG图片(因为PNG图片支持透明)作为窗体的背景图,背景图像布局方式设置为None,窗体Size设置为图片大小
         * 镂空效果就实现了,没有写一句代码。
         * ②:实现了无标题栏窗体的鼠标拖动效果
         * 首先将窗体的边框样式修改为None,让窗体没有标题栏
         * 实现这个效果使用了三个事件:鼠标按下、鼠标弹起、鼠标移动
         * 鼠标按下时更改变量isMouseDown标记窗体可以随鼠标的移动而移动
         * 鼠标移动时根据鼠标的移动量更改窗体的location属性,实现窗体移动
         * 鼠标弹起时更改变量isMouseDown标记窗体不可以随鼠标的移动而移动
         */
        private bool isMouseDown = false;
        private Point FormLocation;     //form的location
        private Point mouseOffset;      //鼠标的按下位置
        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                isMouseDown = true;
                FormLocation = this.Location;
                mouseOffset = Control.MousePosition;
            }

        }

        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            isMouseDown = false;
        }

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            int _x = 0;
            int _y = 0;
            if (isMouseDown)
            {
                Point pt = Control.MousePosition;
                _x = mouseOffset.X - pt.X;
                _y = mouseOffset.Y - pt.Y;

                this.Location = new Point(FormLocation.X - _x, FormLocation.Y - _y);
            }

        }

        private void 关闭ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
    }
}

 

源码Demo上传到CSDN了,资源分一分。下载地址

,

公告

业精于勤,荒于嬉;行成于思,毁于随。

有些事现在不做,一辈子都不会做了
这一刻就计划
下一刻就实施
绝对不给自己找任何退却的理由
做,去做
做了才能有改变,有收获

最新评论

评论最多的文章

访问最多的文章

分类标签

友情链接

存档

TOP
Copyright (c) 2009-2017, b3log.org