VC++深入详解--之复习笔记(五)

本文详细讲解如何使用VC++编写第一个Windows应用程序,从基础出发,涵盖应用程序设置、窗口创建及回调函数等关键知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

10.   动手写第一个Windows程序

到现在为止,读者对创建一个窗口应该有了大致的印象,但是,光看书是不行的,应该试着动手去编写程序。本节的内容就是教读者怎样去编写一个Windows窗口应用程序。完整的例程请参见光盘中的Chapter1目录下的WinMain。
* 启动Microsoft Visual C++6.0,单击【File】菜单,选择【New】菜单项,在“Projects”选项卡下,选择“Win32 Application”,在右侧的“Project name:”文本框中,输入我们的工程名WinMain(如图1.4所示),单击【OK】按钮。
图1.4  创建WinMain新工程
* 在Win32 Application-Step 1 of 1中,选择“An empty project”(如图1.5所示),单击【Finish】按钮。
*  出现一个工程信息窗口,单击 OK 按钮,这样就生成了一个空的应用程序外壳。
* 这样的应用程序外壳并不能做什么,甚至不能运行,我们还要为它加上源文件。单击【File】菜单,选择【New】,在“Files”选项卡下,选择“C++ Source File”,在右侧的“File”文本框中,输入源文件的文件名WinMain(如图1.6所示),单击【OK】按钮。
图1.5  选择An empty project选项
图1.6 添加WinMain.cpp源文件
输入以下代码:
WinMain.cpp
#include <windows.h>
#include <stdio.h>
 
LRESULT CALLBACK WinSunProc(
  HWND hwnd,         // handle to window
  UINT uMsg,         // message identifier
  WPARAM wParam, // first message parameter
  LPARAM lParam     // second message parameter
);
 
int WINAPI WinMain(
  HINSTANCE hInstance,       // handle to current instance
  HINSTANCE hPrevInstance,      // handle to previous instance
  LPSTR lpCmdLine,           // command line
  int nCmdShow                    // show state
)
{
    //设计一个窗口类
    WNDCLASS wndcls;
    wndcls.cbClsExtra=0;
    wndcls.cbWndExtra=0;
    wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
    wndcls.hCursor=LoadCursor(NULL,IDC_CROSS);
    wndcls.hIcon=LoadIcon(NULL,IDI_ERROR);
    wndcls.hInstance=hInstance;     //应用程序实例句柄由WinMain函数传进来
    wndcls.lpfnWndProc=WinSunProc;
    wndcls.lpszClassName="sunxin2006";
    wndcls.lpszMenuName=NULL;
    wndcls.style=CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&wndcls);
 
    //创建窗口,定义一个变量用来保存成功创建窗口后返回的句柄
    HWND hwnd;
    hwnd=CreateWindow("sunxin2006","http://www.sunxin.org",
WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL);
 
    //显示及刷新窗口
    ShowWindow(hwnd,SW_SHOWNORMAL);
    UpdateWindow(hwnd);
 
    //定义消息结构体,开始消息循环
    MSG msg;
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
 
//编写窗口过程函数
LRESULT CALLBACK WinSunProc(
  HWND hwnd,         // handle to window
  UINT uMsg,         // message identifier
  WPARAM wParam, // first message parameter
  LPARAM lParam     // second message parameter
)
{
    switch(uMsg)
    {
    case WM_CHAR:
        char szChar[20];
        sprintf(szChar,"char code is %d",wParam);
        MessageBox(hwnd,szChar,"char",0);
        break;
    case WM_LBUTTONDOWN:
        MessageBox(hwnd,"mouse clicked","message",0);
        HDC hdc;
        hdc=GetDC(hwnd);        //不能在响应WM_PAINT消息时调用
        TextOut(hdc,0,50,"程序员之家",strlen("程序员之家"));
        //ReleaseDC(hwnd,hdc);
        break;
    case WM_PAINT:
        HDC hDC;
        PAINTSTRUCT ps;
        hDC=BeginPaint(hwnd,&ps);       //BeginPaint只能在响应WM_PAINT消息时调用
        TextOut(hDC,0,0,"http://www.sunxin.org",strlen("http://www. sunxin.org"));
        EndPaint(hwnd,&ps);
        break;
    case WM_CLOSE:
        if(IDYES==MessageBox(hwnd,"是否真的结束?","message",MB_YESNO))
        {
            DestroyWindow(hwnd);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd,uMsg,wParam,lParam);
    }
    return 0;
}
如果读者消化吸收了本章的内容,编写上述程序并不难。希望读者仔细思考一下本章所讲的内容,尽量参照每一步中所讲述的知识点,自己将程序编写出来。
提示:不少初学者在编写上述程序时,出现了下面的错误:
--------------Configuration: WinMain - Win32 Debug--------------
Compiling...
WinMain.cpp
Linking...
LIBCD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Debug/WinMain.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.
 
WinMain.exe - 2 error(s), 0 warning(s)
这主要是因为在图1.4所示的步骤中,选错了工程(项目)类型,本章的程序应该选择“Win32 Application”,结果却选择了该类型的下面一个“Win32 Console Application”。在这里,给读者也布置一个任务,在MSDN查找“Win32 Application”和“Win32 Console Application”的说明,弄清楚它们之间的区别。
出现问题的解决办法:
(1)当然是重新建一个工程,选择正确的工程类型(相信读者看了下面的解决方法后,不会选择这一种 J)。
(2)在VC++集成开发环境中,单击菜单【Project】→【Settings】,选择“Link”选项卡,在最下方的“Project Options”列表框中找到“/subsystem:console”后,将其删除,或者修改为“/subsystem:windows”,单击“确定”按钮。重新编译运行程序。

 

 

11.   消息循环的错误分析
下面的代码:
HWND hwnd;
    hwnd=CreateWindow(…);
    MSG msg;
    while(GetMessage(&msg, hwnd,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
注意代码中以粗体显示的部分。这段代码基于这样一个想法:第1章的程序只有一个窗口,而我们前面说了GetMessage函数的hWnd参数是用于指定接收属于哪一个窗口的消息,于是不少人就在消息循环中为GetMessage函数的hWnd参数指定了CreateWindow函数返回的窗口句柄。
读者可以用上述代码中的消息循环部分替换1.5节代码中的消息循环部分,然后运行程序,关闭程序。你会发现你的机器变慢了,同时按下键盘上的Ctrl + Alt + Delete键,启动Windows的任务管理器,切换到“进程”选项卡,单击“CPU”项进行排序,你会发现如图1.7所示的情况。
从图1.7中可以看到,WinMain.exe的CPU占用率接近100,难怪机器“变慢了”。那么这是什么原因呢?实际上这个问题的答案在MSDN中就可以找到,并且就在GetMessage函数的说明文档中。不少初学者在遇到问题时,首先是头脑一片空白,接着就去找人求助,这种思想用在程序开发的学习中,没有什么好处。笔者经常遇到学员问问题,结果有不少问题的答案在MSDN关于某个函数的解释中就可看到(由于显示器的限制,有的答案需要滚动窗口才能看到 J)。所以在这里,笔者也建议读者遇到问题一定要记得查看MSDN,学会使用MSDN并从中汲取知识,将使你受用无穷。
图1.7  WinMain.exe的CPU占用率接近100
回到正题,在1.4.3节介绍GetMessage函数时,曾说过如果hWnd参数是无效的窗口句柄或lpMsg参数是无效的指针时,GetMessage函数将返回-1。当我们关闭窗口时,调用了DestroyWindow来销毁窗口,由于窗口被销毁了,窗口的句柄当然也就是无效的句柄了,那么GetMessage将返回-1。在C/C++语言中,非0即为真,由于窗口被销毁,句柄变为无效,GetMessage总是返回-1,循环条件总是为真,于是形成了一个死循环,机器当然就“变慢了”。J
在MSDN关于GetMessage函数的说明文档中给出了下面的代码:
BOOL bRet;
 
    while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
    {
        if (bRet == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
针对我们这个问题,可以修改上述代码如下:
    HWND hwnd;
    hwnd=CreateWindow(…);
    …
    MSG msg;
    BOOL bRet;
 
    while( (bRet = GetMessage( &msg, hwnd, 0, 0 )) != 0)
    {
        if (bRet == -1)
        {
            // handle the error and possibly exit
            return -1;
        }
        else
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
12.   变量的命名约定
由于Windows程序一般很长,编程人员在一段时间后自己都有可能忘记所定义的变量的含义。为了帮助大家记忆与区分变量,微软公司创建了Windows的命名约定,称之为匈牙利表示法(Hungarian notation)。匈牙利表示法提供了一组前缀字符,如表1.1所示,这些前缀也可以组合起来使用。
1.1  匈牙利表示法
  
  
a
数组
b
布尔值(int
by
无符号字符(字节)
c
字符(字节)
cb
字节记数
rgb
保存RGB颜色值的长整型
cx,cy
短整型(计算x,y的长度)
dw
无符号长整型
fn
函数
h
句柄
i
整数(integer
m_
类的数据成员
n
短整型或整型
np
近指针
p
指针
  
  
l
长整型
lp
长指针
s
字符串
sz
以零结束的字符串
tm
正文大小
w
无符号整型
x,y
无符号整型(表示xy
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值