Win视窗编程和DOS下编程不同,但是类似。Windows应用程序也有它的入口函数,DOS程序中的入口函数是main函数,Windows程序的入口函数是WinMain函数。新建Win32 Application, 选择Empty proj, Finished 完成HelloMsg项目创建。添加HelloMsg.c文件,具体编码如下:

#include <Windows.h>
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine,int iCmdShow)
{
    MessageBox(NULL,"Hello World", "Title", 0);
    return 0;
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

WinMain()函数是入口函数,调用MessageBox()函数之后就返回0结束应用程序。MessageBox()函数的功能就是弹出一个确认对话框,并在这个对话框上显示Hello World. 非常简单,但是它已经脱离了命令行的方式,开始了基于窗口的编程。

Windows消息循环

Windows应用程序是基于窗口的应用程序,而整个Windows操作系统是基于消息驱动的。这就意味着窗口乃至整个系统所发生的事件都被封装为各种各样的消息。OS和APP通过接收消息,分析消息附带的参数信息来进行相关的处理。不管什么语言开发的程序,在WindowsOS上运行都要有一个能够接受并处理消息的循环,这就是Windows程序的核心内容---消息循环机制。

WindowsOS中包括以下几种消息:

1.系统定义的消息

2.应用程序定义的消息

那么消息是如何运作的呢?这里,Windows有一个概念叫做消息队列,OS自己拥有一个消息队列,每个WINDOWS程序也有一个自己的消息队列。系统在有事件发生时,例如,单击鼠标或按下键盘中的某个键,OS就将这个时间转换成一个消息结构,放到自己的消息队列中。根据消息中的句柄将消息分发到应用程序的消息队列中,应用程序使用PeekMessage函数判断是否有消息,使用GetMessage函数取出消息,使用TranslateMessage函数转换消息最后使用DispatchMessage函数将消息分发出去。典型的处理案例如下:

for(;;)
{
    if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) //判断是否消息
    {
        if(GetMessage(&msg,NULL,0,0))//取出消息
        {
            TranslateMessage(&msg);//消息转换
            DispatchMessage(&msg);//分发消息
        }
        else
        {
            break;
        }
    }
}
分发出去之后,OS使用回调机制调用应用程序自己的消息处理函数来处理消息,所谓回调就是与应用程序调用操作系统的API函数相反,由操作系统来调用应用程序的函数个过程叫做回调。一个回调函数示例如下:
LRESULT CALLBACK WndProc(HWND hwnd , UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
        case WM_PAINT:
            //do something
            return 0;
        case WM_KEYDOWN:
            //do something
            return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
    }
 
    return DefWindowProc (hwnd, message, wParam,lParam);
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

在这个函数中,采用switch-case 结构针对不同的消息作不同的处理就是windows程序的核心部分。

GDI绘图

绘图是游戏的第一个任务,其次就是操作即需要响应键盘等输入设备的消息。在windows下绘图最基本的需要就是GDI即 Graphical Device Interface 图像设备接口。GDI函数大致可分析如下4类:

1.取得(或者建立)和释放(或者清除)设备内容的函数, 绘图时需要设备内容句柄。GetDC和RealseDC函数可以在非WM_PAINT的消息处理期间来做到这一点,而BeginPaint和EndPaint函数在进行绘图的WM_PAINT消息处理期间使用。

2.绘图函数,如TextOut函数在窗口的显示区域显示一些文字。

3.设定和取得设备内容参数的函数, 设备内容的"属性"决定有关绘图函数如何工作的细节。例如,用SetTextColor来指定TextOut所绘制的文字色彩。设备内容的所有属性都有默认值,取得设备内容时这些默认值就设定好了。对于所有的Set函数,都有对应的Get函数,以便取得目前设备内容属性。

4.使用GDI对象的函数, GDI对象包括画笔,建立填入封闭区域的画刷、字体、位图等。

注:位图是位的矩形数组,这些位对应于显示设备上的图素,它们是位映射图形的基础工具。位图通常用于在视讯显示器或打印机上显示复杂图像。位图还可以用于显示必须快速绘制的小图像。GDI支持两种形态的位图--旧式的"设备相关"位图(是GDI对象)和新的"设备无关"位图(可以存储在磁盘文件中)。

设备内容的句柄

在绘图之前,首先必须获得一个设备内容的句柄。最常用的取得并释放设备内容句柄的方法是,在处理WM_PAINT消息时,使用BeginPaint和EndPaint调用:

hdc = BeginPaint(hwnd, &ps);

//do something

EndPaint(hwnd, &ps);

变量ps是型态为PAINTSTRUCT的结构,该结构的hdc字段是BeginPaint传回的设备内容句柄。PAINTSTRUCT结构又包含一个名为rcPaint的RECT结构,rcPaint定义一个包围窗口显示区域无效范围的矩形。使用从BeginPaint获得设备内容句柄,只能在这个区域内绘图。BeginPaint调用使该区域有效。

Windows程序还可以在处理非WM_PAINT消息时取得设备内容:

hdc = GetDC(hwnd);

//do something

ReleaseDC(hwnd,hdc);

这个设备内容适用于窗口句柄为hwnd的显示区域。这些调用与BeginPaint和EndPaint的组合之间的基本区别是,利用从GetDC传回的句柄可以在整个显示区域上绘图。当然,GetDC和ReleaseDC不使显示区域中任何可能的无效区域变成有效。

Windows程序还可取得适用于整个窗口(而不仅限于窗口的显示区域)的设备内容句柄:

hdc = GetWindowDC(hwd);

//do something

ReleaseDC(hwnd, hdc);

这个设备内容除了显示区域之外,还包括窗口的标题列、菜单、滚动条和框架。GetWindowDC函数很少使用,如果想尝试使用它,则必须拦截处理WM_NCPAINT消息,Windows使用该消息在窗口的非显示区域上绘图。

BeginPaint,GetDC和GetWindowDC获得的设备内容都与视讯显示器上的某个特定窗口相关。取得设备内容句柄的另一个更通用的函数是CreateDC:

hdc = CreateDC(pszDriver, pszDevice,pszOutput, pData);

// do something

DeleteDC(hdc);

也可通过在调用GetDC时使用一个NULL参数,从而取得整个屏幕的设备内容句柄。使用位图时,取得一个"内存设备内容"有时有用:

hdcMem = CreateCompatibleDC(hdc);

//do something

DeleteDC(hdcMem);

可以将位图选进内存设备内容,然后使用GDI函数在位图上绘图。

可以通过使用CreatePen或CreatePenIndirect函数来自定义一个"逻辑画笔",因为这些函数在创建画笔时不需要设备内容句柄作为参数,即通过这两个函数创建的画笔是与设备无关的逻辑画笔,直到调用SelectObject之后,画笔才与设备内容发生联系。因此,可以对不同的设备使用相同的逻辑画笔。

CreatePen创建画笔:

hpen = CreatePen(ipenStyle, iwidth,crcolor);

ipenStyle是画笔的样式,可以是:PS_SOLID,PS_NULL等值,iWidth是画笔宽度如果为0, 则代表画笔宽度为一个像素,如果在选择画笔样式为点线或虚线的同时 iWidth宽度值设置为大于1,那么windows将采用实线画笔来代替这些虚线画笔来画。尤其在支持缩放图像中使用这些虚线时要特别注意,一旦缩放的线宽超过1它们就变成了实线。crColor是笔的颜色

也可以通过建立一个型态为LOGPEN(逻辑画笔)的结构,然后调用CreatePenIndirect()来创建画笔。

LOGPEN  logPen;

LOGPEN 结构有lopnStyle,lopnWidth和lopnColor(COLORREF)三个变量。

然后将结构的地址传递给CreatePenIndirect来创建画笔:

hpen = CreatePenIndirect(&logpen);

定义画笔是一种"GDI对象",所以使用完之后要删除自定义的GDI对象,如DeleteObject(hpen);

GDI位图对象

GDI位图对象有时也称为设备相关位图(DDB).DDB是Windows图形设备接口的图形对象之一(其中还包括绘图笔,画刷,字体,metafile和调色盘)。这些图形对象存储在GDI模块内部,由应用程序软件以句柄数字的方式引用。可以将DDB句柄存储在一个HBITMAP(handle to a Bitmap, 位图句柄)型态的变量中。

HBITMAP hBitmap;

然后,通过调用DDB建立的一个函数来获得句柄,如CreateBitmap

CreateBitmap函数用法如下:

hBitmap = CreateBitmap(cx,cy, cPlanes,cBitsPixel,bits);

CreateBitmap函数配置并初始化GDI内存中的一些内存来存储关于位图的信息以及实际位图的信息,前两个参数是位图的宽度和高度(以像素为单位),第三个参数是颜色面的数目,第四个参数是每个像素的位数,第五个参数是指向一个以特定颜色格式存储的位数组的指针,数组内存放有用来初始化该DDB的图像。如果不想用一张现有的图像来初始化DDB,可以将最后一个参数设为NULL。

当程序使用完位图以后,就要清除这段内存:

DeleteObject(hBitmap);

可以用CreateCompatibleBitmap来简化问题:

hBitmap = CreateCompatibleBitmap(hdc, cx, cy);

此函数建立一个与设备兼容的位图,hdc即此设备的内容句柄。通常设备内容指的是特殊的图形输出设备(例如显示器或打印机)以及其设备驱动程序。内存设备内容只位于内存中,它不是真正的图形输出设备,可以说与指定的真正的设备"兼容"。要建立一个内存设备内容,首先要有实际设备的设备内容句柄,如果是hdc, 可以用如下方法来建立内存设备内容:

hdcMem = CreateCompatibleDC(hdc);

建立的内存设备内容最终必须通过DeleteDC来删除。

C语言进入界面编程准备篇的更多相关文章

  1. 界面编程模仿篇(QQ登录界面逼真篇)

    写了好多天的爬虫,偷空前前后后用了两天的时间(排除吃饭睡觉)写完了这个QQ登录界面,看起来还凑和着吧,如果是的大神的,莫见笑,纯属业余作品,废话先不多说,截图如下,其中第二幅图片中的红色方框部份有待完 ...

  2. Windows界面编程第五篇 静态控件背景透明化(13篇)

    上一篇<Windows界面编程第三篇 异形窗体 普通版>和<Windows界面编程第四篇异形窗体 高富帅版>介绍了异形窗口(异形窗体)的创建,并总结出了异形窗口的“三要素”: ...

  3. C语言控制台窗体图形界面编程(总结)

    本系列文章是笔者通过学习<C语言控制台窗体界面编程(修正版)>而写(关于此文档的很多其它信息请看本系列文章第一篇),旨在让大家更加清晰简洁easy地学习C语言控制台窗体界面的编程. 通过本 ...

  4. 【转】Shell编程基础篇-上

    [转]Shell编程基础篇-上 1.1 前言 1.1.1 为什么学Shell Shell脚本语言是实现Linux/UNIX系统管理及自动化运维所必备的重要工具, Linux/UNIX系统的底层及基础应 ...

  5. Python入门 —— 03GUI界面编程

    GUI(Graphical User Interface) 即图形用户接口,又称图形用户接口. 是指采用图形方式显示的计算机操作用户界面.GUI 是屏幕产品的视觉体验和互动操作部分. "你的 ...

  6. C语言嵌入式系统编程修炼

    C语言嵌入式系统编程修炼 2008-08-19 作者:宋宝华 来源:天极网 C语言嵌入式系统编程修炼之背景篇 本文的讨论主要围绕以通用处理器为中心的协议处理模块进行,因为它更多地牵涉到具体的C语言编程 ...

  7. C语言之基本编程思想与基本概念扫盲

    前言:C语言是包含了很多编程的基本思想,理解C能够有助于理解其他高级语言,深刻理解编程很多基本思想:这对新手入门是有很多好处的,正所谓磨刀不误砍柴工,内功与基础修炼扎实了,才能开始盖高楼大厦. 这篇文 ...

  8. 试读《JavaScript语言精髓与编程实践》

    有幸看到iteye的活动,有幸读到<JavaScript语言精髓与编程实践_第2版>的试读版本,希望更有幸能完整的读到此书. 说来读这本书的冲动,来得很诡异,写一篇读后感,赢一本书,其实奖 ...

  9. Linux C 程序 GTK+图形界面编程(22)

    GTK+图形界面编程 Linux大多是在字符界面,但也可以开发图形界面 目前已经存在多种Linux下开发图形界面的程序开发包:最常用的是Qt和GTK+ Qt是一个跨平台的图形界面开发库,不仅仅支持Li ...

随机推荐

  1. js layui 分页脚本

    //分页 layui.use(['laypage'], function(){ var laypage = layui.laypage; laypage.render({ elem: 'page' , ...

  2. DEV Express中ImageCollection的使用

    1,        ImageCollection作为窗体组件的一种,位于Components分类下,拖进窗体以后,显示在界面的底部. 2,        注意ImageCollection的Imag ...

  3. [数据结构]C#基于数组实现泛型顺序表

    前方预警,只完成了顺序表的插入/删除/查找. 错误代码示例: /// <summary> /// 查找顺序表第i个位置的元素 /// 在显示情况中,我们更常用下标 /// </sum ...

  4. 配置工程文件dll编译后copy路径

    放到工程文件的最后面的配置节点: 下面的配置节点中生成路径换成实际的相对路径就可以了 修改:Prject.csproj 文件里面的配置节点  project配置节点里面的最后面 <Target ...

  5. Oracle数据库学习之存储过程--提高程序执行的效率

    存储过程是Oracle开发者在数据转换或查询报表时经常使用的方式之一.它就是想编程语言一样一旦运行成功,就可以被用户随时调用,这种方式极大的节省了用户的时间,也提高了程序的执行效率.存储过程在数据库开 ...

  6. 大数据学习——Linux-SSH报错:Could not resolve hostname centos02: Temporary failure in name resolution

    https://blog.csdn.net/mcb520wf/article/details/83303792 随笔异常 ssh: Could not resolve hostname centos0 ...

  7. python014 Python3 迭代器与生成器

    Python3 迭代器与生成器迭代器迭代是Python最强大的功能之一,是访问集合元素的一种方式..迭代器是一个可以记住遍历的位置的对象.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结 ...

  8. python-001 第一个Python3.x程序 hello world

    我们可以使用以下命令来查看我们使用的Python版本: (d:\ProgramData\Anaconda3) C:\Users\Administrator.2016-20160920ET>pyt ...

  9. FZU-2148-Moon Game,,几何计算~~

    Problem 2148 Moon Game Time Limit: 1000 mSec Memory Limit : 32768 KB  Problem Description Fat brothe ...

  10. 【转】关于大型网站技术演进的思考(十九)--网站静态化处理—web前端优化—上(11)

    网站静态化处理这个系列马上就要结束了,今天我要讲讲本系列最后一个重要的主题web前端优化.在开始谈论本主题之前,我想问大家一个问题,网站静态化处理技术到底是应该归属于web服务端的技术范畴还是应该归属 ...