浅析如何用C#.NET做屏幕截图软件以及注册全局快捷键(下)

下面来说第三种方法:模拟PrintScreen按键,访问CliPBoard来获得屏幕截图,继而执行截取操作。

  1、模拟PrintScreen按键为我们省去了很多代码,但刚开始也给我带来了很大的费解,假如你想通过button_click事件调用API来模拟按下 PrintScreen键,然后通过Clipboard.GetImage()去获取剪贴板里面的图片,那样结果只有一个:失败!也许你认为是我们在调用 Clipboard.GetImage()时模拟按键还未完成操作,然后我们在它们中间加个Thread.Sleep(0),很遗憾,结果还是一样。我怀疑是鼠标点击button和模拟PrintScreen按键两者之间的紊乱造成的,在此就不多说废话了,本人想到的解决方法就是使用 backgroundWorker来执行按键处理,这样就分离了窗体线程和模拟按键之间的紊乱问题。

  C#模拟键盘按键的实现:

  模拟键盘要用到user32.dll里面的keybd_event

  原型如下:

[DllImport("user32.dll")]
static extern void keybd_event(
 byte bVk,// 虚拟键值
 byte bScan,// 
硬件扫描码
 uint dwFlags,// 动作标识
 UIntPtr dwExtraInfo// 与键盘动作关联的辅加信息
);

  其中,bVk表示虚拟键值,其实它是一个BYTE类型值的宏,其取值范围为1-254。有关虚拟键值表请在MSDN上使用关键字“Virtual- Key Codes”查找相关资料。bScan表示当键盘上某键被按下和放开时,键盘系统硬件产生的扫描码我们可以MapVirtualKey()函数在虚拟键值与扫描码之间进行转换,一般可以设置为0。dwFlags表示各种各样的键盘动作,应用程序可使用如下一些预定义常数的组合设置标志位,KEYEVENTF_EXETENDEDKEY=1:若指定该值,则扫描码前一个值为OXEO(224)的前缀字节。 DEYEVENTF_KEYUP=2:若指定该值,该键将被释放;若未指定该值,该键交被接下。dwExtralnfo:定义与击键相关的附加的32位值。C#模拟PrintScreen按键示例如下,

public static void PrintScreen() {
            IceApi.keybd_event( (byte)0x2c, 0, (uint)0, IntPtr.Zero );//down
            IceApi.keybd_event( (byte)0x2c, 0, (uint)2, IntPtr.Zero );//up
        }

  贴一下button的处理,见截图~:

 

  我们把click之后的事情都交给backgroundWorker去做,省去了很多很多麻烦问题。

  接下来是开始进入真正的截图阶段。首先New一个窗体SnapForm,设置如下属性:

this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Opacity = 0.99;
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.TopMost = true;
this.
Windowstate =System.Windows.Forms.FormWindowState.Maximized;

  修改构造函数为(见截图):

  当窗体显示时,就已经是全屏幕的截图了。

  之后,我们可以在form上面放个PictureBox,然后在PictureBox_Paint里面画线和矩形。

  示例:

picBox_Paint

private void picBox_Paint( object sender, PaintEventArgs e ) {
            Graphics g = e.Graphics;
            if (isDrawing) {
                //g.DrawRectangle( penRect, captureRect);
                DrawScableRect( captureRect, g );
            }
            else if (!isDrawned) {
                g.DrawLine( penLine, 0, currentPoint.Y, fullScreen.Width, currentPoint.Y );
                g.DrawLine( penLine, currentPoint.X, 0, currentPoint.X, fullScreen.Height );
            }
        }

  首先我们需要在鼠标按下时记录矩形的起点,

if (!isDrawing) {
                    startPoint = e.Location;
                    captureRect.Location = startPoint;
                    isDrawing = true;
                    return;
                }

  然后在MouseMove事件里面刷新矩形大小,最后调用this.Refresh(),强制窗体重绘,调用Paint方法。

  最最后是在MouseUp事件里面检测画图是否完成。这样就停止调用this.Refresh()了。

  至于画图形,就要用到Graphics.DrawRectangle()和Graphics.DrawLine(),可以到MSDN查询它们的使用方法。

在MouseMove事件里面,我们可以检测鼠标的当前位置,然后设置鼠标形状,继而可以实现矩形的拖动以及扩大和缩小。

  在此不详赘述了。

  关于截图保存,我们可以加个MouseDoubleClick事件。在下面,我是直接从原始图片截取矩形覆盖区域的,

  利用orgbmp.Clone( captureRect, screenSnap.PixelFormat )来复制我们需要的区域,这样既保证了截取图片的

  图像质量,也避免了考虑矩形边框问题。

  MouseDoubleClick

private void SnapForm_MouseDoubleClick( object sender, MouseEventArgs e ) {
            if (e.Button==MouseButtons.Left) {
                Bitmap orgbmp = new Bitmap( screenSnap );
                try {
                    Bitmap ab = orgbmp.Clone( captureRect, screenSnap.PixelFormat );
                    if (saveDlg.ShowDialog() == DialogResult.OK) {
                        ab.Save( saveDlg.FileName, imgFormat[Path.GetExtension( saveDlg.FileName )] );
                        MessageBox.Show( "Completed!" );
                    }
                }
                catch { }
                finally { orgbmp.Dispose(); }
            }
        }

  这样C#截图就基本说完了,为了美化,我们可以在截图窗体上面放个半透明图层,做出类似QQ截图的效果。

最后说说在C#里面如何来自定义鼠标的样式,以及定义全局快捷键来实现截图。

  1、自定义鼠标的样式:假如你只用C#里面的Managed Code,自定义出的鼠标结果显示出来的会变成单色。

  我们需要user32.dll里面的几个API来实现自定义彩色鼠标样式。

C# Signature:
[DllImport("user32.dll")]
static extern IntPtr LoadCursorFromFile(string lpFileName);
 
[DllImport( "user32.dll" )]
public static extern uint DestroyCursor( IntPtr cursorHandle );

  这两个都比较简单,我们可以在form_load时加载鼠标句柄,记得最后要在form_closing时释放句柄资源~

  this.Cursor = new Cursor( IntPtr handle )用来实例化鼠标。

  2、全局快捷键或称热键,则需要调用user32里面的另外两个API来实现。

[DllImport( "user32.dll", SetLastError = true )]
public static extern bool Re
GISterHotKey(
        IntPtr hWnd, // handle to window  
        int id, // hot key identifier  
        KeyModifiers fsModifiers, // key-modifier options  
        System.
Windows.Forms.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
}

 

  比如注册F3键为截图快捷键:RegisterHotKey( this.Handle, 7890, IceApi.KeyModifiers.None, Keys.F3 );

  这两个API分别要放到Form_Load和Form_FormClosed事件里面。

  最后,我们需要截获系统消息来为我们定义的快捷键执行相应操作。此时我们需要重写WndProc

  WndProc

protected override void WndProc( ref Message m ) {
            switch (m.Msg) {
                //hotkey pressed
                case 0x0312:
                    if (m.WParam.ToString() == "7890") {
                        GlobalKeyProc( this.WindowState == FormWindowState.Minimized );
                    }
                    break;
            }
            base.WndProc( ref m );
        }

  在GlobalKeyProc()里面处理我们需要的工作。

  出处:http://1971ruru.cnblogs.com/

你可能感兴趣的:(api,object,user,C#,byte,button)