http://hi.baidu.com/3582077/item/77d3c1ff60f9fa5ec9f33754

调用API函数,在窗口非客户区绘图

GDI+的Graphics类里有个FromHdc函数,这个函数可以根据窗口设备上下文(DC)创建Graphics对象,在vc++中,窗口客户区与非客户区的绘图无非就是GetWindowDC和GetDC函数的不同调用。前者获得整个窗口DC,后者获得窗口客户区DC。

那么我们就可以在C#里,调用GetWindowDC函数获取整个窗口DC,然后通过FromHdc加载进去,这样我们就能针对整个窗口绘图了。

C#要如何调用WINDOWS API呢,或者说如何调用动态链接库(DLL)里的函数。

跟VC++的大同小异,先导入动态链接库,然后再声明API函数,如下:

[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern IntPtr GetWindowDC(IntPtr hwnd);

当然上面是最简单的,还有一些细节没有讲,先就这样吧,会基本使用就行了,那些细节问题以后再详细说明。

GetWindowDC函数可以参考:http://hi.baidu.com/3582077/blog/item/14bb7201f559eb187bec2cab.html第八十六个参数。

在C#中,我们发现API函数的参数类型都不一样了,比如在VC++中的句柄HDC,HWND。在这里声明时,都用了IntPtr代替,这是没有办法的事,因为C#没有指针这个概念,而我们通过查HDC,和HWND类型定义时发现,它们都是指针类型。

所以在C#中,这些“句柄”类型都用IntPtr代替,包括区域句柄HRGN,HICON图标,HFONT字体句柄等。

看一个示例吧,(接着上一章的)

public partial class Form1 : Form
    {
        //导入动态链接库,声明函数,这个函数是声明在Form1类里的。
        [System.Runtime.InteropServices.DllImport("User32.dll")]
        private static extern IntPtr GetWindowDC(IntPtr hwnd);
        //存储PNG非透明部分的路径
        private GraphicsPath path = new GraphicsPath();
        //加载PNG图片
        Bitmap bmp = new Bitmap("d:\\Image\\win.png");
        public Form1()
        {
            InitializeComponent();
            //判断每个像素的颜色值,获取图片的显示区域
            for (int y = 0; y < bmp.Height; y++)
                for (int x = 0; x < bmp.Width; x++)
                {
                    Color cor = bmp.GetPixel(x, y);
                    int argb = cor.ToArgb();
                    byte[] bargb = BitConverter.GetBytes(argb);
                    //像素颜色值不是透明的
                    if (bargb[3] != 0)
                    {
                        //把这个像素点区域添加到路径里去
                        path.AddRectangle(new Rectangle(x, y, 1, 1));
                    }
                }
            //设置窗口显示区域,通过路径创建区域
            this.Region = new Region(path);
            this.Paint += formPaint;
         
        }
        private void formPaint(object sender, PaintEventArgs e)
        {
          
            OnPaintBackground(e);
            //Handle是窗口句柄,它是一个IntPtr类型
            IntPtr hdc = GetWindowDC(this.Handle);
            //根据窗口DC创建Graphics对象
            Graphics gr = Graphics.FromHdc(hdc);
            //绘制图片
            gr.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height));
        }
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            //透明画刷填充
            //base.OnPaintBackground(e);
            e.Graphics.FillRectangle(Brushes.Transparent, this.ClientRectangle);
        }

}

效果图:

怎么样,效果不错吧,但一拖动窗口就原形毕露了,注意到苹果下方的阴影了么,就是为了实现这个效果才会带来一些问题,或者说麻烦了许多吧。只是我没去解决。移动窗口,或者最大化窗口,都没有完全刷新整个窗口,才会导致这种问题出现。这个问题留待以后解决吧,

在兴趣的朋友也可以去解决一下这个问题。

另外,我用透明画刷填充的只是窗口的客户区,如果想填充整个窗口(包括标题栏),方法跟在整个窗口绘图一样,获得WindowDC,然后

创建Graphics对象,绘制窗口背景。

(题外话:在vc++中,客户区与非客户区有着不同的重绘消息,WM_PAINT和WM_NCPAINT,这一点要注意了,在刷新非客户区的时候,别重绘客户区,虽说不会出什么问题,但影响了效率总是不好的,能避免就避免)

自绘窗口非客户区(包括标题栏,最大,最小化,关闭按钮)

重写消息处理函数WndProc

消息机制参考http://hi.baidu.com/3582077/blog/item/6a6c2c0990627fda3bc763a2.html里的CreateWindow函数

看一个示例:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0xA3)//WM_NCLBUTTONDBLCLK  双击标题消息
                MessageBox.Show("你双击了标题栏");
            //默认消息处理
            base.WndProc(ref m);
        }

}

这样双击标题栏的时候就会给出一个提示,然后再默认处理。

查消息对应的数值,可以到VC++编译器里去查,比如打上WM_LBUTTONDOWN然后右击,选择转到定义就可以查看了。

m.HWnd存储有窗口句柄,m.LParam和m.WParam是消息的附带信息,可以参考CreateWindow函数里的WPARAM和LPARAM参数解释。

自绘非客户区工作量实在是太大了,这里我只给个大概的思路,方向,以后有空再来做吧。

前提当然是把各项数据计算出来,比如窗口有无边框,如果有的话,获取边框宽度,高度,然后计算四个边框的矩形区域。

最后就判断窗口有无最大,最大小化属性,然后获得三个按钮的区域。

而SystemInformation类里就存储有这些数据,比如SystemInformation.CaptionButtonSize存储有标题栏按钮的大小,得到了大小,就可以

确定按钮的区域了,因为这三个按钮都在窗口的右上角,除去边框的高宽。

而SystemInformation.CaptionHeight存储有标题栏的高度,边框的高宽存储在SystemInformation.BorderSize或者SystemInformation.Border3DSize,这个根据窗口的FormBorderStyle决定。窗口的是否处于最大化可以判断MaximizeBox,为true最大化。

得到了上面那些数据,就响应非客户区的各种消息,如鼠标左键消息WM_NCLBUTTONDOWN和WM_NCLBUTTONUP。

鼠标移动消息WM_NCMOUSEMOVE,接着就开始自绘了。

另Rectangle类里的Contains函数,可以判断一个点是否在一个矩形区域内。

http://blog.csdn.net/jiangxinyu/article/details/8097759

调用API函数,在窗口非客户区绘图(通过GetWindowDC获得整个窗口的DC,就可以随意作画了)的更多相关文章

  1. VC----SDK下对窗口非客户区的操作

    窗口分成两大部分:客户区和非客户区.非客户区再次细分:标题栏,如图片中顶部深蓝色:左边框,如图片中红色部分:上边框,如图片中绿色部分:右边框,如图片中右侧天蓝色部分:底边框,如图片中下面棕色部分. 之 ...

  2. C#调用API函数EnumWindows枚举窗口的方法

    原文 http://blog.csdn.net/dengta_snowwhite/article/details/6067928 与C++不同,C#调用API函数需要引入.dll文件,步骤如下: 1. ...

  3. C# 绘制窗体客户非客户区要用WM_PAINT和WM_NCPAINT

    窗体分为两部分:客户区(Client area)和非客户区(Non-Client area) WM_PAINT消息.OnPaint()方法.GetDC()API函数都是处理窗体客户区绘制的   而标题 ...

  4. Delphi - Windows系统下,Delphi调用API函数和7z.dll动态库,自动把文件压缩成.tar.gz格式的文件

    项目背景 应欧美客户需求,需要将文件压缩成.tar.gz格式的文件,并上传给客户端SFTP服务器. 你懂的,7-Zip软件的显著特点是文件越大压缩比越高,在Linux系统上相当于我们Windows系统 ...

  5. Delphi调用API函数获取Windows目录信息、获取System目录信息、获取Temp临时文件目录信息

    var Str1, Str2: Array[..Max_Path]of Char;//开辟缓冲区 Str3: Array[..]of Char; begin GetWindowsDirectory(@ ...

  6. 调用API函数减少c#内存占用(20+m减至1m以下)

    原文:调用API函数减少c#内存占用(20+m减至1m以下) c#虽然内置垃圾回收机制,但是并不能解决程序占用内存庞大的问题,如果我们仔细观察任务管理器,我们会发现一个程序如果最小化的时候,它所占用的 ...

  7. windows 屏幕坐标 窗口坐标 客户区坐标 逻辑坐标 设备坐标之间的关系及转换

    设置坐标映射    (1)Windows坐标系统 Windows坐标系分为逻辑坐标系和设备坐标系两种,GDI支持这两种坐标系.一般而言, GDI的文本和图形输出函数使用逻辑坐标,而在客户区移动或按下鼠 ...

  8. 实现:调用API函数ShowWindow()来隐藏窗口

    只需要将相应代码复制即可. 代码如下: #include <iostream> #include <windows.h> int main() { HWND hDos; //声 ...

  9. 老话题:自己编写只截窗口客户区的截屏软件(VB2010)

    现在能实现截屏的软件很多,就不一一列举了,连WIN7都自带截屏软件,甚至OFFICE2010开始都有截屏的功能. 截屏软件虽多,无外乎三种截屏方式:全屏截图.窗口截图.自定义矩形截图. 其中,窗口截图 ...

随机推荐

  1. padding与margin的差别

    之前一直没有搞懂android:padding和android:layout_margin的差别,事实上概念非常easy,padding是站在父view的角度描写叙述问题,它规定它里面的内容必须与这个 ...

  2. Qt知识点、疑难杂症的治疗

    Q: QVariant 保存指针数据   A1: 1,使用QVariant::fromValue((void*)target)保存数据 2,使用(ShortcutItem*)(v.value<v ...

  3. Linux驱动开发学习的一些必要步骤

      1. 学会写简单的makefile 2. 编一应用程序,可以用makefile跑起来 3. 学会写驱动的makefile 4. 写一简单char驱动,makefile编译通过,可以insmod, ...

  4. xcode6制作IOS .a静态库小记

    xcode6制作IOS .a静态库小记 创建iOS静态库 简单写个打印的代码 编码完成之后,直接Run就能成功生成.a文件了,选择 xCode->Window->Organizer-> ...

  5. Android滚动截屏,ScrollView截屏

    在做分享功能的时候,需要截取全屏内容,一屏展示不完的内容,一般我们会用到 ListView 或 ScrollView 一: 普通截屏的实现 获取当前Window 的 DrawingCache 的方式, ...

  6. linux之CentOS-7.0环境搭建

    此文作为新手安装centos-7的图文教程.  一.  前言 最近,师兄要进行实验室架构搭建,需要学习docker.而docker是完全依赖于linux系统的.所以,有了这篇文章. linux有很多发 ...

  7. JS HTML 单引号与双引号

    JS中,单引号和双引号其实没啥区别,看你自己习惯了. 但若双引号中再使用双引号,我们可采取"外双内单"或者"外单内双"的格式,当然如果需要的是双引号本身,则只能 ...

  8. Java 8 Lambda表达式10个示例【存】

    PS:不能完全参考文章的代码,请参考这个文件http://files.cnblogs.com/files/AIThink/Test01.zip 在Java 8之前,如果想将行为传入函数,仅有的选择就是 ...

  9. OD: Vulnerabilities Analyze Skills

    第五篇了,漏洞分析案例 漏洞利用的灵活程度让这门技术变得似乎没有什么原则可言,只有实践后总结提高才能挥洒自如. 漏洞分析方法 目标:弄清攻击原理.评估潜在利用方式及风险等级.扎实的漏洞利用技术是进行漏 ...

  10. WIN10FTP服务器搭建

    在WIN10上搭建FTP服务器 先建立两个文件夹,区分上传和下载,做测试 用 然后在管理--服务界面新建一个用户 用户目录下创建一个用户 因为服务应用程序里面没有IIS,所以我们打开控制面板里面的程序 ...