C/C++编写Windows窗口应用程序(Win32程序),非黑漆漆的控制台窗口

 Windows应用程序是基于消息驱动的,任何线程只要注册窗口类都会有一个消息队列用于接收用户输入的消息和系统消息。

一、 窗口的创建流程

创建一个完整的窗口需要经过下面四个操作步骤:

  1. 设计一个窗口类(填写Win32程序必要信息)

  2. 注册窗口类

  3. 创建窗口

  4. 显示及更新窗口


二、相关函数及术语

1、WinMain函数

// Windows程序的入口函数,C/C++是main函数
int WINAPI WinMain(
    HINSTANCE hInstance,      // 实例的句柄
    HINSTANCE hPrevInstance,  // 没有意义。它在16位窗口中使用,但现在总是0
    LPSTR lpCmdLine,          // 包含命令行参数作为一个Unicode字符串
    int nCmdShow              // 显示标志
);

2、窗口类

// 创建窗口所要信息
typedef struct {
    UINT style;             //窗口类型
    WNDPROC lpfnWndProc;    //回调函数,由系统调用
    int cbClsExtra;         //类的额外附加字节数
    int cbWndExtra;         //窗口的额外附加字节数
    HINSTANCE hInstance;    //实例句柄
    HICON hIcon;            //图标样式
    HCURSOR hCursor;        //光标样式
    HBRUSH hbrBackground;   //背景颜色
    LPCTSTR lpszMenuName;   //菜单名称
    LPCTSTR lpszClassName;  //窗口类名称
} WNDCLASS, *PWNDCLASS;

3、关于句柄

  • 句柄(HANDLE),资源的标识。
  • 操作系统要管理和操作这些资源,都是通过句柄来找到对应的资源。按资源的类型,又可将句柄细分成图标句柄(HICON),光标句柄(HCURSOR),窗口句柄(HWND),应用程序实例句柄(HINSTANCE)等等各种类型的句柄。操作系统给每一个窗口指定的一个唯一的标识号即窗口句柄。

4、MSG结构定义

typedef struct {
    HWND hwnd;     //消息发向窗口的句柄
    UINT message;  //消息标识符。这是一个数值,用以标识消息。
    WPARAM wParam; //个32位的消息参数,其含义和数值根据消息的不同而不同。
    LPARAM lParam; //一个32位的消息参数,其值与消息有关。
    DWORD time;    //消息放入消息队列的时间
    POINT pt;      //消息放入消息队列时鼠标的坐标
} MSG, *PMSG;

 5、回调函数

  • 回调函数是由系统调用的,只需要在设计窗口类当中,指定回调函数名就可以了。
  • 一般在回调函数中处理各种消息,如对键盘输入的处理,对鼠标点击的处理等。
// 回调函数名可以改,只要在窗口类那里填写好对应的名称就可以
// 参数个数和各类型不能随便更改
LRESULT CALLBACK WindowProc(
    HWND hwnd,     //窗口句柄
    UINT uMsg,     //指定消息类型
    WPARAM wParam, //指定其余的、消息特定的信息。该参数的内容与UMsg参数值有关。
    LPARAM lParam  //指定其余的、消息特定的信息。该参数的内容与UMsg参数值有关。
);

三、实例代码

#include <stdio.h>
#include <windows.h>

//回调函数声明
LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);

//Win32应用程序入口
int WINAPI WinMain(
    HINSTANCE hInstance,      // 当前应用程序实例
    HINSTANCE hPrevInstance,  // 32位程序没用,总为0
    LPSTR lpCmdLine,          // 命令行参数
    int nCmdShow              // 显示状态
)
{
    char szTitle[] = "任逍遊 --- [专用空间]";
    char szClassName[] = "简单问题复杂化";

    // 1.设计窗口类
    WNDCLASS wndcls; //窗口类

    //填写窗口类相应的信息(必要)
    wndcls.cbClsExtra = 0;  //类的额外附加字节数
    wndcls.cbWndExtra = 0;  //窗口额外的附加字节数
    wndcls.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH); //背景颜色
    wndcls.hCursor = LoadCursor(NULL,IDC_ARROW); //光标样式
    wndcls.hIcon = LoadIcon(NULL,IDI_WINLOGO);   //图标样式
    wndcls.hInstance = hInstance;           //实例句柄
    wndcls.lpfnWndProc = WindowProc;        //回调函数,由系统调用
    wndcls.lpszClassName = szClassName;	    //窗口类名称
    wndcls.lpszMenuName = NULL;             //菜单名字
    wndcls.style = CS_HREDRAW | CS_VREDRAW; //窗口类型,这里是水平重画跟垂直重画

    // 2.注册窗口类
    RegisterClass(&wndcls);

    // 3.创建窗口
    HWND hwnd;
    hwnd=CreateWindow(
             szClassName,         //窗口类名称,必须跟上面填写的一样,否则显示不了窗口
             szTitle,             //窗口标题
             WS_OVERLAPPEDWINDOW, //指定要创建的窗口的样式
             0,0,                 //窗口位置
             600,400,             //窗口大小
             NULL,                //父窗口
             NULL,                //菜单
             hInstance,           //实例句柄,WinMain函数参数
             NULL                 //窗口创建数据
         );

    // 4.显示窗口
    ShowWindow(hwnd,SW_SHOWNORMAL);
    UpdateWindow(hwnd); //刷新窗口

    // 循环获取消息
    MSG msg;
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg); //转换消息(如:WM_CHAR),只会产生新的消息,不会销毁原由消息
        // WM_CHAR消息由WM_KEYDOWN消息和WM_KEYUP消息组成
        DispatchMessage(&msg);  //将消息传给窗口回调函数
    }
    return 0;
}

//回调函数,处理各种消息,由系统调用
LRESULT CALLBACK WindowProc(
    HWND hwnd,      // 窗口句柄
    UINT uMsg,      // 指定消息类型
    WPARAM wParam,  // 第一个消息参数
    LPARAM lParam   // 第二条消息参数
)
{
    char szMotto[] = "天若有情天亦老,人间正道是沧桑。";
    char szOut[] = "简单问题复杂化";
    switch(uMsg)
    {
    case WM_PAINT:                                    /* 窗口重绘消息 */
        HDC hDC;
        PAINTSTRUCT ps;
        hDC = BeginPaint(hwnd,&ps);               //指定窗口进行绘图工作的准备
        TextOut(hDC,0,0,szMotto,strlen(szMotto)); //窗口上输出文字
        EndPaint(hwnd,&ps);                       //绘图结束,释放绘图区
        /*
        BeginPaint和EndPaint只能在WM_PAINT消息中使用,不能在其它消息在使用
        BeginPaint和EndPaint是一对的,BeginPaint函数创建的DC不能用ReleaseDC去释放
        GetDC获取到的DC也不能使用EndPaint来释放
        */
        break;
    case WM_CHAR:                                     /* 键盘输入事件 */
        char szChar[20];
        sprintf(szChar,"键盘输入: %c(%d)",wParam,wParam);
        MessageBox(hwnd,szChar,"任逍遊",0); //弹出消息对话框
        break;
    case WM_LBUTTONDOWN:                              /* 鼠标单击事件 */
        MessageBox(hwnd,"鼠标单击事件发生了","任逍遊",0);
        HDC hdc;
        hdc = GetDC(hwnd);   //获取窗口DC句柄
        TextOut(hdc,0,50,szOut,strlen(szOut));
        ReleaseDC(hwnd,hdc); //释放DC
        /*GetDC和ReleaseDC是一对的*/
        break;
    case WM_CLOSE:                                    /* 关闭窗口消息 */
        if(IDYES==MessageBox(hwnd,"是否真的结束?","任逍遊",MB_YESNO))
        {
            // 会发送WM_DESTROY 和 WM_NCDESTROY 消息
            DestroyWindow(hwnd); //销毁窗口,进程并没有结束
        }
        break;
    case WM_DESTROY:                                  /* 销毁消息 */
        PostQuitMessage(0);      //请求进程退出
        break;
    default:
        return DefWindowProc(hwnd,uMsg,wParam,lParam); //缺省消息处理,必不可少!
    }
    return 0;
}

程序运行截图

  • 7
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C++写的一个简单的界面演示系统 void CMiniDrawDoc::AddFigure (CFigure *PFigure) { m_FigArray.Add (PFigure); SetModifiedFlag (); } CFigure *CMiniDrawDoc::GetFigure (int Index) { if (Index m_FigArray.GetUpperBound ()) return 0; return (CFigure *)m_FigArray.GetAt (Index); } int CMiniDrawDoc::GetNumFigs () { return m_FigArray.GetSize (); } void CMiniDrawDoc::DeleteContents() { // TODO: Add your specialized code here and/or call the base class int Index = m_FigArray.GetSize (); while (Index--) delete m_FigArray.GetAt (Index); m_FigArray.RemoveAll (); CDocument::DeleteContents(); } void CMiniDrawDoc::OnEditClearAll() { // TODO: Add your command handler code here DeleteContents (); UpdateAllViews (0); SetModifiedFlag (); } void CMiniDrawDoc::OnUpdateEditClearAll(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->Enable (m_FigArray.GetSize ()); } void CMiniDrawDoc::OnEditUndo() { // TODO: Add your command handler code here int Index = m_FigArray.GetUpperBound (); if (Index > -1) { delete m_FigArray.GetAt (Index); m_FigArray.RemoveAt (Index); } UpdateAllViews (0); SetModifiedFlag (); } void CMiniDrawDoc::OnUpdateEditUndo(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->Enable (m_FigArray.GetSize ()); } // implementation of figure classes: IMPLEMENT_SERIAL (CFigure, CObject, 3) CRect CFigure::GetDimRect () { return CRect (min (m_X1, m_X2), min (m_Y1, m_Y2), max (m_X1, m_X2) + 1, max (m_Y1, m_Y2) + 1); } void CFigure::Serialize (CArchive& ar) { if (ar.IsStoring ()) ar << m_X1 << m_Y1 << m_X2 << m_Y2 <> m_X1 >> m_Y1 >> m_X2 >> m_Y2 >> m_Color; } IMPLEMENT_SERIAL (CLine, CFigure, 3) CLine::CLine (int X1, int Y1, int X2, int Y2, COLORREF Color, int Thickness) { m_X1 = X1; m_Y1 = Y1; m_X2 = X2; m_Y2 = Y2; m_Color = Color; m_Thickness = Thickness; } void CLine::Serialize (CArchive& ar) { CFigure::Serialize (ar); if (ar.IsStoring ()) ar <> m_Thickness; } void CLine::Draw (CDC *PDC) { CPen Pen, *POldPen; // select pen/brush: Pen.CreatePen (PS_SOLID, m_Thickness, m_Color); POldPen = PDC->SelectObject (&Pen); // draw figure: PDC->MoveTo (m_X1, m_Y1); PDC->LineTo (m_X2, m_Y2); // remove pen/brush: PDC->SelectObject (POldPen); } IMPLEMENT_SERIAL (CRectangle, CFigure, 3) CRectangle::CRectangle (int X1, int Y1, int X2, int Y2, COLORREF Color, int Thickness) { m_X1 = X1; m_Y1 = Y1; m_X2 = X2; m_Y2 = Y2; m_Color = Color; m_Thickness = Thickness; } void CRectangle::Serialize (CArchive& ar) { CFigure::Serialize (ar); if (ar.IsStoring ()) ar <> m_Thickness; } void CRectangle::Draw (CDC *PDC) { CPen Pen, *POldPen; // select pen/brush: Pen.CreatePen (PS_INSIDEFRAME, m_Thickness, m_Color); POldPen = PDC->SelectObject (&Pen); PDC->SelectStockObject (NULL_BRUSH); // draw figure: PDC->Rectangle (m_X1, m_Y1, m_X2, m_Y2); // remove pen/brush: PDC->SelectObject (POldPen); } IMPLEMENT_SERIAL (CRectFill, CFigure, 3) CRectFill::CRectFill (int X1, int Y1, int X2, int Y2, COLORREF Color) { m_X1 = min (X1, X2); m_Y1 = min (Y1, Y2); m_X2 = max (X1, X2); m_Y2 = max (Y1, Y2); m_Color = Color; } void CRectFill::Draw (CDC *PDC) { CBrush Brush, *POldBrush; CPen Pen, *POldPen; // select pen/brush: Pen.CreatePen (PS_INSIDEFRAME, 1, m_Color); POldPen = PDC->SelectObject (&Pen); Brush.CreateSolidBrush (m_Color); POldBrush = PDC->SelectObject (&Brush); // draw figure: PDC->Rectangle (m_X1, m_Y1, m_X2, m_Y2); // remove pen/brush: PDC->SelectObject (POldPen); PDC->SelectObject (POldBrush); } IMPLEMENT_SERIAL (CRectRound, CFigure, 3) CRectRound::CRectRound (int X1, int Y1, int X2, int Y2, COLORREF Color, int Thickness) { m_X1 = min (X1, X2); m_Y1 = min (Y1, Y2); m_X2 = max (X1, X2); m_Y2 = max (Y1, Y2); m_Color = Color; m_Thickness = Thickness; } void CRectRound::Serialize (CArchive& ar) { CFigure::Serialize (ar); if (ar.IsStoring ()) ar <> m_Thickness; } void CRectRound::Draw (CDC *PDC) { CPen Pen, *POldPen; // select pen/brush: Pen.CreatePen (PS_INSIDEFRAME, m_Thickness, m_Color); POldPen = PDC->SelectObject (&Pen); PDC->SelectStockObject (NULL_BRUSH); // draw figure: int SizeRound = (m_X2 - m_X1 + m_Y2 - m_Y1) / 6; PDC->RoundRect (m_X1, m_Y1, m_X2, m_Y2, SizeRound, SizeRound); // remove pen/brush: PDC->SelectObject (POldPen); } IMPLEMENT_SERIAL (CRectRoundFill, CFigure, 3) CRectRoundFill::CRectRoundFill (int X1, int Y1, int X2, int Y2, COLORREF Color) { m_X1 = min (X1, X2); m_Y1 = min (Y1, Y2); m_X2 = max (X1, X2); m_Y2 = max (Y1, Y2); m_Color = Color; } void CRectRoundFill::Draw (CDC *PDC) { CBrush Brush, *POldBrush; CPen Pen, *POldPen; // select pen/brush: Pen.CreatePen (PS_INSIDEFRAME, 1, m_Color); POldPen = PDC->SelectObject (&Pen); Brush.CreateSolidBrush (m_Color); POldBrush = PDC->SelectObject (&Brush); // draw figure: int SizeRound = (m_X2 - m_X1 + m_Y2 - m_Y1) / 6; PDC->RoundRect (m_X1, m_Y1, m_X2, m_Y2, SizeRound, SizeRound); // remove pen/brush: PDC->SelectObject (POldPen); PDC->SelectObject (POldBrush); } IMPLEMENT_SERIAL (CCircle, CFigure, 3) CCircle::CCircle (int X1, int Y1, int X2, int Y2, COLORREF Color, int Thickness) { m_X1 = min (X1, X2); m_Y1 = min (Y1, Y2); m_X2 = max (X1, X2); m_Y2 = max (Y1, Y2); m_Color = Color; m_Thickness = Thickness; } void CCircle::Serialize (CArchive& ar) { CFigure::Serialize (ar); if (ar.IsStoring ()) ar <> m_Thickness; } void CCircle::Draw (CDC *PDC) { CPen Pen, *POldPen; // select pen/brush: Pen.CreatePen (PS_INSIDEFRAME, m_Thickness, m_Color); POldPen = PDC->SelectObject (&Pen); PDC->SelectStockObject (NULL_BRUSH); // draw figure: PDC->Ellipse (m_X1, m_Y1, m_X2, m_Y2); // remove pen/brush: PDC->SelectObject (POldPen); } IMPLEMENT_SERIAL (CCircleFill, CFigure, 3) CCircleFill::CCircleFill (int X1, int Y1, int X2, int Y2, COLORREF Color) { m_X1 = min (X1, X2); m_Y1 = min (Y1, Y2); m_X2 = max (X1, X2); m_Y2 = max (Y1, Y2); m_Color = Color; } void CCircleFill::Draw (CDC *PDC) { CBrush Brush, *POldBrush; CPen Pen, *POldPen; // select pen/brush: Pen.CreatePen (PS_INSIDEFRAME, 1, m_Color); POldPen = PDC->SelectObject (&Pen); Brush.CreateSolidBrush (m_Color); POldBrush = PDC->SelectObject (&Brush); // draw figure: PDC->Ellipse (m_X1, m_Y1, m_X2, m_Y2); // remove pen/brush: PDC->SelectObject (POldPen); PDC->SelectObject (POldBrush); }
以下是在VC2010中编写Win32窗口应用程序的基本步骤: 1. 打开VC2010,选择“新建项目”。 2. 在“新建项目”对话框中,选择“Win32控制台应用程序”并命名您的项目。 3. 在“应用程序类型”对话框中,选择“Windows应用程序”并勾选“空项目”选项。 4. 单击“确定”按钮创建项目。 5. 在“解决方案资源管理器”中,右键单击“源文件”文件夹并选择“添加”>“新建项”。 6. 在“添加新项”对话框中,选择“C++文件”并命名您的文件。 7. 在您的源文件中,编写WinMain函数和窗口过程函数。 8. 在您的WinMain函数中,调用CreateWindow函数创建窗口。 9. 在您的窗口过程函数中,处理您需要处理的窗口消息。 10. 在您的窗口过程函数中,处理WM_DESTROY消息并调用PostQuitMessage函数以退出应用程序。 11. 编译并运行您的应用程序。 以下是一个简单的Win32窗口应用程序示例: ```c++ #include <Windows.h> LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 注册窗口类 WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = "MyWindowClass"; RegisterClass(&wc); // 创建窗口 HWND hWnd = CreateWindow("MyWindowClass", "Win32 Window Application", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hInstance, NULL); // 显示窗口 ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // 消息循环 MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 10, 10, "Hello, Win32 Window Application!", strlen("Hello, Win32 Window Application!")); EndPaint(hWnd, &ps); break; } case WM_DESTROY: { PostQuitMessage(0); break; } default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } ``` 这个示例创建一个简单的窗口,并在窗口中绘制一些文本。请注意,这只是一个简单的示例,您可以根据您的需要进行更改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值