• 一个截屏工具制作的全过程记录——如何使用“拿来主义”


    第一部分,截屏功能的实现

    利用关键字“.netcapture speicified area”在Google中搜索现成的答案,从答案中,我直接进行“相面”,打开看起来比较满足条件的第二和第三条记录。


    逐个打开搜索结果看一看,比较符合我的要求的是“http://stackoverflow.com/questions/3306600/c-how-to-take-a-screenshot-of-a-portion-of-screen”,代码如下:

    Rectangle rect= new Rectangle(0, 0, 100, 100);
    Bitmap bmp =new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb);
    Graphics g =Graphics.FromImage(bmp);
    g.CopyFromScreen(rect.Left,rect.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
    bmp.Save(fileName,ImageFormat.Jpeg);

    这份代码的作用就是自定义一个处于屏幕内的一块矩形区域,然后截取矩形区域内的屏幕图像。

    第二部分,矩形工具的实现

    Google关键字“C#how to resize a none border form”,第一条就是答案!


    代码如下:

      public partial class Form1 : Form {
        public Form1() {
          InitializeComponent();
          this.FormBorderStyle = FormBorderStyle.None;
          this.DoubleBuffered = true;
          this.SetStyle(ControlStyles.ResizeRedraw, true);
        }
    
        private const int cGrip = 16;      // Grip size
        private const int cCaption = 25;   // Caption bar height;
    
        protected override void OnPaint(PaintEventArgs e) {
          Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip, this.ClientSize.Height - cGrip, cGrip, cGrip);
          ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
          rc = new Rectangle(0, 0, this.ClientSize.Width, 32);
          e.Graphics.FillRectangle(Brushes.DarkBlue, rc);
        }
     
        protected override void WndProc(ref Message m) {
    
          if (m.Msg == 0x84) {  // Trap WM_NCHITTEST
            Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
            pos = this.PointToClient(pos);
            if (pos.Y < cCaption) {
              m.Result = (IntPtr)2;  // HTCAPTION
              return;
            }
            if (pos.X >= this.ClientSize.Width - cGrip && pos.Y >= this.ClientSize.Height - cGrip) {
              m.Result = (IntPtr)17; // HTBOTTOMRIGHT
              return;
            }
          }
          base.WndProc(ref m);
    
        }
      }

    上段代码实现了一个可拖拽、可调节大小的无边框样式的窗体。重点内容有两处,一个是标题栏的自绘,另一个是对用户交互区域的绘制。因为截图工具并不需要标题栏,所以完全可以把下面的代码删除,这样自绘的标题栏就不会显示。

          rc = new Rectangle(0, 0, this.ClientSize.Width, 32);
          e.Graphics.FillRectangle(Brushes.DarkBlue, rc);

    虽然自绘标题栏消失了,但WndProc还是会检测用户压下鼠标动作,并把客户区坐标小于cCaption的动作当作压下标题栏来处理。而我真正需要的是拖拽整个窗体,而非只是针对标题栏,所以需要把pos.Y < cCaption的限定范围扩大,所以修改后的代码应该如下:

            if (pos.X >= this.ClientSize.Width - cGrip && pos.Y >= this.ClientSize.Height - cGrip)
            {
              m.Result = (IntPtr)17; // HTBOTTOMRIGHT
              return;
            } else {
              m.Result = (IntPtr)2;  // HTCAPTION
              return;
            }
    

    先处理右下角与用户交互的可调整窗体大小的提示区域,然后把非客户区的其它消息当作标题栏交互消息处理,这样就可以实现窗体拖拽的效果了。

    对于窗体大小调整的功能,程序中分两步实现:第一步是在protected override void OnPaint(PaintEventArgs e)中绘制了一个交互性图标,用户通过它可以对窗体的大小进行调节;第二步则是将非客户区,且鼠标处于指定范围内的消息,当作HTBOTTOMRIGHT处理,即右下角的调节大小(当然,也可以为八个方向编写对应的处理,其它的可用值见http://msdn.microsoft.com/en-us/library/windows/desktop/ms645618%28v=vs.85%29.aspx)。

    现在已经完美地解决了拖拽,在测试阶段却发现标题栏特有的附加功能——双击。怎么屏蔽呢?从代码中可用看出,我们一直都在处理WM_NCHITTEST消息,其余的消息都用默认的base.WndProc处理了。为了能够达到屏蔽的效果,可用添加一个双击消息的处理,即不做任何处理

          if(m.Msg == 0xA3)       // WM_NCLBUTTONDBLCLK
          {
            m.Result = IntPtr.Zero;                   
            return;
          }

    第三部分:如何设置半透明效果:

    Google关键字“c#transparent form”,第一条为答案!

    BackColor = Color.Lime;
    TransparencyKey = Color.Lime;

    运行一下看效果,且慢!不对啊,画面上什么都没有了,完全看不到窗体!回想了一下,TransparencyKey会将画面中指定的颜色部分搞成全透明的,所以就什么都看不见了。这时又想到了Opacity,OK,搞定!

    关于透明,这里要多提一句,TransparencyKey和Opacity,前者功能是让指定颜色完全透明,后者则是让窗体半透明,在后面完整的源码中,我会给出相应的代码例子。

    第四部分,全局热键


    Google关键字“c#global shortcut key for my exe”,这个稍微复杂了些,从答案中并没有直接给出代码,但从推荐的网站“http://www.dreamincode.net/forums/topic/180436-global-hotkeys/”中我们可以找到现成代码可以下载。但是公司的Policy比较严,不能随便下,所以放弃。


    换个关键字“c#global shortcut key example”,第一个就是答案:http://stackoverflow.com/questions/3654787/global-hotkey-in-console-application,代码也有贴出,内容有点长,请参考后面的完整源码部分。


    第五部分,图像保存

    有了上面的调查结果,我们差不多已经调查完80%的功能了,剩下的基本上就是一些使用上的功能,在这个截图工具中,我打算采用两种保存图片的功能:一个是直接保存到内存中,这样方便直接粘贴到Word这样的高级编辑器中,还有一种就是弹出SaveDialog对话框,让用户自行选择保存地址,生成物理文件。使用关键字“c# copybitmap to clipboard”可以很容易地找到第一种方法的答案,而关于第二种这里就不多做解释了,“http://msdn.microsoft.com/en-us/library/sfezx97z.aspx”里有完整的答案。


    下面是把截图保存到内存的实现代码,关键内容就是Clipboard.SetImage:

            private void button1_Click(object sender, EventArgs e)
            {
                Rectangle r = this.RectangleToScreen(ClientRectangle);
                Bitmap b = GetDesktopImage(r);
                Clipboard.SetImage(b);
            }
    
     
    
            public Bitmap GetDesktopImage(Rectangle rect)
            {
                Graphics graphics;
                Bitmap bitmap;
    
                bitmap = new Bitmap(rect.Width, rect.Height);
                graphics = Graphics.FromImage(bitmap);
                graphics.CopyFromScreen(rect.Left, rect.Top, 0, 0, new Size(rect.Width, rect.Height));
                return bitmap;
            }

    文件保存成物理文件可以参考“http://stackoverflow.com/questions/457370/c-how-to-convert-bitmap-byte-array-to-jpeg-format”,代码如下:

        using(Image img = Image.FromFile("foo.bmp"))
        {
            img.Save("foo.jpg", ImageFormat.Jpeg);
        }

    注意,在调用文件保存到内存时,代码会执行出错,原因可能是OLE对象的问题。通过“http://stackoverflow.com/questions/798464/how-to-invoke-with-action”的答案可以找到解决方案。

    参考方案

    解决方案

    地址

    跨线程访问控件

    http://stackoverflow.com/questions/798464/how-to-invoke-with-action

    全局快捷键

    http://stackoverflow.com/questions/3654787/global-hotkey-in-console-application

    SaveDialog用法

    http://msdn.microsoft.com/en-us/library/sfezx97z.aspx

    禁用双击

    http://stackoverflow.com/questions/9588540/how-can-i-stop-a-double-click-of-the-window-title-bar-from-maximizing-a-window-o

    保存屏幕截图到内存

    http://www.codekeep.net/snippets/abc85672-d163-46df-99a1-1ac993074f56.aspx

    保存图片到磁盘

    http://stackoverflow.com/questions/457370/c-how-to-convert-bitmap-byte-array-to-jpeg-format

    按键参考大全

    http://msdn.microsoft.com/en-us/library/system.windows.forms.keys%28v=vs.71%29.aspx

    非客户区WM_NCHITTEST消息参考

    http://msdn.microsoft.com/en-us/library/windows/desktop/ms645618%28v=vs.85%29.aspx

    禁止关闭

    C# prevent closing

    隐藏与显示

    Form.Visible = !Form.Visible

    系统托盘

    C# system tray

    http://alanbondo.wordpress.com/2008/06/22/creating-a-system-tray-app-with-c/

        public interface SystemTrayHandler
        {
            void OnSystemTrayShow(object sender, EventArgs e);
            void OnSystemTrayExit(object sender, EventArgs e);
        }
    
        public class SystemTrayLoader
        {
            public static void WrapFormWithSysTray(SystemTrayHandler handler)
            {
                // Create a simple tray menu with only one item.
                ContextMenu trayMenu = new ContextMenu();
                trayMenu.MenuItems.Add("Show Infected Area", handler.OnSystemTrayShow);
                trayMenu.MenuItems.Add("Exit Shotit", handler.OnSystemTrayExit);
     
                // Create a tray icon. In this example we use a
                // standard system icon for simplicity, but you
                // can of course use your own custom icon too.
                NotifyIcon trayIcon = new NotifyIcon();
                trayIcon.Text = "Shotit by wooooody```";
                trayIcon.Icon = new Icon(SystemIcons.Application, 40, 40);
     
                // Add menu to tray icon and show it.
                trayIcon.ContextMenu = trayMenu;
                trayIcon.Visible     = true;
            }
        }

    双击系统托盘

    http://www.developer.com/net/net/article.php/3336751/C-Tip-Placing-Your-C-Application-in-the-System-Tray.htm

    C# double click system tray

    内存中默认保存Png格式

    http://stackoverflow.com/questions/3517965/convert-bmp-to-png-in-memory-for-clipboard-pasting-in-net


  • 相关阅读:
    repadmin example.
    在 Windows 2000 和 Windows XP 中重置计算机帐户
    管理活动目录
    使用AdsiEdit工具查看GC数据
    mms链接media player 9.0无法打开
    活动目录的复制之细节
    使用Repadmin.exe 对活动目录复制排错
    Difference among Domain Local Group and Global Group and Universal Group
    使用 ADSI Edit 编辑 Active Directory 属性
    xp的密码工具
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/3027061.html
Copyright © 2020-2023  润新知