Windows --- 第一个Windows窗口程序

#include<Windows.h>

//窗口程序的入口函数: WinMain
//控制台窗口应用程序入口函数: main

//WinMain 有四个参数
//WINAPI: 函数调用约定
int /*WINAPI*/ WinMain(HINSTANCE hInstance,HINSTANCE hPreInstance,LPSTR lpCmdLine,int nCmdShow)
{
	MessageBox(NULL, L"Hello world!", L"温馨提示", MB_OK);
    return 0;
}  

1>C:\Users\Desktop\WindowsProject1\WindowsProject1\WindowsProject1.cpp(7,5): 
warning C4007: “WinMain”: 必须是“__stdcall”

#define CALLBACK    __stdcall
#define WINAPI      __stdcall
#define APIENTRY    WINAPI
#define APIPRIVATE  __stdcall
#define PASCAL      __stdcall

WINAPI、CALLBACK、APIENTRY. . . 函数调用约定,本质是 __stdcall:标准调用方式

约定了:① 函数的入栈方式 ② 由谁来平衡堆栈

约定了 WinMain 的四个参数是从左往右入栈还是从右往左入栈 nCmdShow→  lpCmdLine→  hPreInstance→  hInstance

规定了清理栈的操作:是由调用者来清理还是被调用者来清理

WinMain 调用 MessageBox,调用者 WinMain 进行释放,MessageBox 是被调者

#define WINAPIV     __cdecl

__cdecl 是 C语言 中常用的函数 printf,scanf 的调用约定,也是从右往左入栈

 HINSTANCE:应用程序实例句柄类型

//通过一个宏来声明一个句柄
DECLARE_HANDLE(HINSTANCE);

//宏定义
#define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name

#define DECLARE_HANDLE(name) 
struct name##__
{
    int unused;
}; 
typedef struct name##__ *name


#define DECLARE_HANDLE(HINSTANCE) 
struct HINSTANCE##__
{
    int unused;
}; 
typedef struct HINSTANCE##__ *HINSTANCE

##:宏定义连接符

//定义了HINSTANCE,指向结构体的指针
#define DECLARE_HANDLE(HINSTANCE) 
struct HINSTANCE__
{
    int unused;
}; 
typedef struct HINSTANCE__* HINSTANCE

hInstance:当前应用程序实例句柄

开一次程序是一个实例句柄,开两个是两个实例句柄 . . . 实例句柄就代表当前程序

hPreInstance:当前程序的前一个实例句柄

第三个程序的前一个实例句柄是第二个程序

在 32 位机器和 64 位机器上已经废弃了,现在不再使用,值为 NULL,是一个空指针

在 16 位机器上使用

LPSTR:char*

typedef _Null_terminated_ CHAR *NPSTR, *LPSTR, *PSTR;

//CHAR* 等价于 NPSTR, LPSTR, PSTR
typedef  CHAR *NPSTR, *LPSTR, *PSTR;

//CHAR 等价于 char
typedef char CHAR;

lpCmdLine:命令行参数

 

nCmdShow:窗口的显示方式

最大化,最小化,普通,正常显示

MessageBox:弹出一个消息提示框

int MessageBox(
  [in, optional] HWND    hWnd,
  [in, optional] LPCTSTR lpText,
  [in, optional] LPCTSTR lpCaption,
  [in]           UINT    uType
);

HWND:窗口句柄类型(可以理解为窗口的ID)

传入 NULL 表示没有父窗口句柄,窗口是独立的

DECLARE_HANDLE            (HWND);

#define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name

#define DECLARE_HANDLE(name) 
struct name##__
{    
    int unused;
}; 
typedef struct name##__ *name

//结构体指针
#define DECLARE_HANDLE(HWND) 
struct HWND__
{    
    int unused;
}; 
typedef struct HWND__ *HWND

LPCTSTR  lpText:显示内容

//Unicode编码
//LPCWSTR 等价于 PCTSTR, LPCTSTR
typedef LPCWSTR PCTSTR,LPCTSTR;

//CONST WCHAR* 等价于 LPCWSTR, PCWSTR
typedef _Null_terminated_ CONST WCHAR *LPCWSTR, *PCWSTR;

//CONST 等价于 const
#define CONST               const

//wchar_t 等价于 WCHAR
#ifndef _MAC
typedef wchar_t WCHAR;    // wc,   16-bit UNICODE character
#else
// some Macintosh compilers don't define wchar_t in a convenient location, or define it as a char
typedef unsigned short WCHAR;    // wc,   16-bit UNICODE character
#endif

//const char_t* 等价于 LPCTSTR

//多字节字符集
//const char* 等价于 LPCTSTR

lpCaption:对话框的标题,是一个字符串

如果此参数为 NULL ,则默认标题为 Error

统一采用 Unicode 字符集,在 Windows API 中的函数,字符串前面都需要加 L,表示为宽字符集

 

 

UINT    uType:按钮和图标的组合(用位运算 | )

注意:不能按钮和按钮组合、不能图标和图标组合

MB_OK:确定按钮

MB_YESNO:是、否按钮

MB_YESNOCANCEL:是、否、取消按钮

 MessageBox 的返回值:点击了哪个按钮就返回哪个按钮,按钮的值是一个整数

#define MB_OK                       0x00000000L
#define MB_OKCANCEL                 0x00000001L
#define MB_ABORTRETRYIGNORE         0x00000002L
#define MB_YESNOCANCEL              0x00000003L
#define MB_YESNO                    0x00000004L
#define MB_RETRYCANCEL              0x00000005L
#if(WINVER >= 0x0500)
#define MB_CANCELTRYCONTINUE        0x00000006L
#endif /* WINVER >= 0x0500 */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int nCmdShow)
{
	int n = MessageBox(NULL, L"Hello world!", L"温馨提示", MB_YESNO);
	if (n == IDYES)
	{
		MessageBox(NULL, L"点击YES", L"提示", MB_OK);
	}
	else if (n == IDNO)
	{
		MessageBox(NULL, L"点击NO", L"提示", MB_OK);
	}
	return 0;
}

 

 

创建一个 Windows 程序

什么是 API ?

类似 printf,scanf,strlen 等函数

由 Windows 操作系统提供的接口:创建窗口、弹出消息提示框,关闭窗口,显示窗口,更新窗口 . . .

把这些接口称为应用程序编程接口 (Application Programma Interface)

Windows API 函数

什么是 SDK(资源的集合) ?

软件开发包(Software Development Kit)

包含了:API 函数库、帮助手册、辅助工具、使用文档

什么是窗口 ?

包含:标题栏、菜单栏、系统菜单、最小化框、最大化框、滚动条

窗口主要分为客户区和非客户区

客户区盖在非客户区上

什么是句柄 ?

在 Windows 中有很多句柄,用于标志一个资源,或者标志一个窗口

窗口句柄、图标句柄、光标句柄、菜单句柄、进程句柄、线程句柄

如果不小心把项目工程建为控制台项目,会导致报错:建立 Win32 控制台工程,入口函数应该是 main 函数

可以重新建立工程,或者按如下操作:

1.设计窗口类

//第一个参数:窗口句柄  结构体
//当前窗口的窗口句柄

//第二个参数:用无符号整型存储消息编号  unsigned int
//鼠标在窗口中点一下会有鼠标点击和鼠标抬起消息、鼠标在屏幕上移动有鼠标移动消息...

//第三个参数:WPARAM  unsigned int
//窗口附加信息-> 鼠标点击的坐标

//第四个参数:LPARAM long
//窗口附加信息

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

//窗口处理函数
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    { 
    //窗口关闭消息
    case WM_CLOSE:
        MessageBox(NULL,L"点了关闭按钮",L"提示",MB_OK);      
        //销毁当前处理的窗口句柄-> 发出 WM_DESTROY 信息
        DestroyWindow(hWnd);
        break;
    //窗口销毁消息
    case WM_DESTROY: 
        //发出一个退出消息 WM_QUIT -> 传入0正常退出
        PostQuitMessage(0);
        break;

    }
    //调用操作系统默认窗口处理函数
    //如果不想自己处理、处理不了...调用这个函数就交给操作系统处理
	return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

WINUSERAPI
VOID
WINAPI
PostQuitMessage(
    _In_ int nExitCode);

//窗口类型名 宽字节用两个字节来存储一个字符
//字符数组
wchar_t szAPPClassName[] = L"EDU_GUI";

//窗口标题
wchar_t szWindowName[] = L"这是我的第一个Windows程序";

//结构体变量
WNDCLASS wc;
//窗口类的风格
//当窗口在水平方向和竖直方向发生变化就让它重绘
wc.style = CS_HREDRAW | CS_VREDRAW;
//窗口处理函数
wc.lpfnWndProc = WindowProc;
//窗口类的额外拓展空间大小(字节)-> 窗口类想额外存储一些信息可以存储多少个字节自己决定 默认值为0 
wc.cbClsExtra = 0;
//窗口的额外拓展空间大小(字节)-> 窗口创建好后窗口里面想附带一些数据可以给它准备一块空间 默认值为0 
wc.cbWndExtra = 0;
//当前应用程序实例句柄
wc.hInstance = hInstance;
//窗口左上角的图标句柄-> NULL:没有图标
wc.hIcon = NULL;
//光标图标句柄-> 鼠标放在窗口上显示的图标 NULL:没有图标
wc.hCursor = NULL;
//背景画刷句柄-> 可以放图片 0:最暗-> 255:最亮 
//白色:RGB(255,255,255)    红色:RGB(255,0,0)
wc.hbrBackground = CreateSolidBrush(RGB(255,255,255));
//菜单名
wc.lpszMenuName = NULL;
//窗口类型名
wc.lpszClassName = szAPPClassName;

//W 表示使用 Unicode 字符集
typedef struct tagWNDCLASSW {
    UINT        style;
    WNDPROC     lpfnWndProc;
    int         cbClsExtra;
    int         cbWndExtra;
    HINSTANCE   hInstance;
    HICON       hIcon;
    HCURSOR     hCursor;
    HBRUSH      hbrBackground;
    LPCWSTR     lpszMenuName;
    LPCWSTR     lpszClassName;
} WNDCLASSW, *PWNDCLASSW, NEAR *NPWNDCLASSW, FAR *LPWNDCLASSW;
#ifdef UNICODE
typedef WNDCLASSW WNDCLASS;

typedef LONG_PTR            LRESULT;
typedef _W64 long LONG_PTR, *PLONG_PTR;

//无符号整型
typedef unsigned int        UINT;

typedef UINT_PTR            WPARAM;
typedef _W64 unsigned int UINT_PTR, *PUINT_PTR;

typedef LONG_PTR            LPARAM;
typedef _W64 long LONG_PTR, *PLONG_PTR;

//窗口类的风格
#define CS_VREDRAW          0x0001
#define CS_HREDRAW          0x0002
#define CS_DBLCLKS          0x0008
#define CS_OWNDC            0x0020
#define CS_CLASSDC          0x0040
#define CS_PARENTDC         0x0080
#define CS_NOCLOSE          0x0200
#define CS_SAVEBITS         0x0800
#define CS_BYTEALIGNCLIENT  0x1000
#define CS_BYTEALIGNWINDOW  0x2000
#define CS_GLOBALCLASS      0x4000

#define CS_IME              0x00010000
#if(_WIN32_WINNT >= 0x0501)
#define CS_DROPSHADOW       0x00020000
#endif /* _WIN32_WINNT >= 0x0501 */

//操作系统默认窗口处理函数 参数类型都一样
WINUSERAPI
#ifndef _MAC
LRESULT
WINAPI
#else
LRESULT
CALLBACK
#endif
DefWindowProcW(
    _In_ HWND hWnd,
    _In_ UINT Msg,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam);
#ifdef UNICODE
#define DefWindowProc  DefWindowProcW
#else
#define DefWindowProc  DefWindowProcA
#endif // !UNICODE

LRESULT:表示一个处理结果

typedef LONG_PTR            LRESULT;

typedef _W64 long LONG_PTR, *PLONG_PTR;

RGB 宏函数

#define RGB(r,g,b)          ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))

HICON 句柄类型

//声明一个句柄
DECLARE_HANDLE(HICON);

H 开头的一般是句柄类型

2.注册窗口类

if(0 == RegisterClass(&wc))
{
    MessageBox(NULL,L"此程序不能运行在Windows NT上",L"温馨提示",MB_OK);
    return 0;
}

ATOM
WINAPI
RegisterClassW(
    _In_ CONST WNDCLASSW *lpWndClass);
#ifdef UNICODE
#define RegisterClass  RegisterClassW

typedef WORD                ATOM;   //BUGBUG - might want to remove this from minwin

//一个字占两个字节
typedef unsigned short      WORD;
//双字占四个字节
typedef unsigned long       DWORD;

3.创建窗口

窗口样式详见:Window Styles (Winuser.h) - Win32 apps | Microsoft Docs

HWND hWnd = CreateWindow(
    szAppClassName,                                                   //注册窗口的类型名
    szWindowName,                                                     //窗口的标题
    WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINMIZEBOX,         //窗口的风格 标题栏|系统菜单
    200,                                                              //窗口距离屏幕左上角横坐标
    200,                                                              //窗口距离屏幕左上角纵坐标
    800,                                                              //窗口的宽度
    600,                                                              //窗口的高度
    NULL,                                                             //父窗口句柄
    NULL,                                                             //菜单句柄
    hInstance,                                                        //应用程序实例句柄
    NULL,                                                             //创建窗口时需要传递的信息 NULL:没有要传递的
);

if(NULL == hWnd)
{
    MessageBox(NULL,L"创建窗口失败",L"温馨提示",MB_OK);
    return 0;
}

#define CreateWindow  CreateWindowW

#define CreateWindowW(lpClassName, lpWindowName, dwStyle, x, y,\
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)\
CreateWindowExW(0L, lpClassName, lpWindowName, dwStyle, x, y,\
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)

 

 

4.显示窗口

//要显示的窗口 怎么显示:普通显示
ShowWindow(hWnd,SW_SHOW);
WINUSERAPI
BOOL
WINAPI
ShowWindow(
    _In_ HWND hWnd,
    _In_ int nCmdShow);

 

5.更新窗口

UpdateWindow(hWnd);

WINUSERAPI
BOOL
WINAPI
UpdateWindow(
    _In_ HWND hWnd);

6.消息循环

处理关闭:点击了关闭按钮,程序的进程并没有结束

点击关闭按钮,有很多消息

MSG msg;
//只要收到 WM_QUIT 消息 函数返回值为0 while循环结束
//不断从消息队列中获取消息,把获取到的消息保存到 GetMessage
//消息编号是一个编号 0,1,2,3...一般所有消息都要获取
while(GetMessage(&msg,NULL,0,0))
{
    //将虚拟键消息转为字符消息
    //当在键盘上按下某个字符,比如按下A,产生按下消息和抬起消息,把这两个消息转为字母 A 需要通过以下函数
    TranslateMessage(&msg);
    //将虚拟键消息分发给窗口处理函数
    DispatchMessage(&msg);
}

typedef struct tagMSG {
    HWND        hwnd;                //消息发给哪一个窗口的窗口句柄
    UINT        message;             //消息编号
    WPARAM      wParam;              //附加消息
    LPARAM      lParam;              //附加消息
    DWORD       time;                //消息投放到消息队列里面的时间
    POINT       pt;                  //消息放入消息队列的时候鼠标的坐标
#ifdef _MAC
    DWORD       lPrivate;
#endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;

typedef struct tagPOINT
{
    LONG  x;
    LONG  y;
} POINT, *PPOINT, NEAR *NPPOINT, FAR *LPPOINT;


WINUSERAPI
BOOL
WINAPI
GetMessageW(
    _Out_ LPMSG lpMsg,
    _In_opt_ HWND hWnd,              //NULL:获取当前窗口以及它的子窗口的所有消息
    //想过滤哪些消息编号
    _In_ UINT wMsgFilterMin,         //获取大于...的消息
    _In_ UINT wMsgFilterMax);        //获取小于...的消息
#ifdef UNICODE
#define GetMessage  GetMessageW

 

Windows 消息机制原理

消息队列是用于存储消息的

操作系统会把信息分发给消息队列

通过 GetMessage 不断从消息队列中循环取消息,应用程序接收到消息后通过 DispatchMessage 分发给操作系统,让操作系统调用窗口处理函数,让窗口处理函数做出响应,执行需要执行的内容

加载图标 .ico、光标 .cur

注意:不能直接改后缀名

exe 的图标由编号最小的决定,把最小的放最上面

注意打开文件拓展名

把素材放在工程目录下

 

 

#include"resource.h"
//窗口左上角的图标句柄-> NULL:没有图标  通过 MAKEINTRESOURCEA 把整数转换为字符串
//都属于自定义资源
//vs手绘
wc.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_MAIN));
//导入
wc.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_LOGO));

//光标图标句柄-> 鼠标放在窗口上显示的图标 
//系统资源
wc.hCursor = LoadCursor(NULL,IDC_CROSS);
//自定义资源
wc.hCursor = LoadCursor(hInstance,MAKEINTRESOURCE(IDC_CURSOR));

//加载一个图标文件
WINUSERAPI
HICON
WINAPI
LoadIconW(
    _In_opt_ HINSTANCE hInstance, //应用程序实例句柄:如果是系统资源传NULL,如果是自定义资源传hInstance
    _In_ LPCWSTR lpIconName);     //资源ID
#ifdef UNICODE
#define LoadIcon  LoadIconW

//加载一个光标文件
WINUSERAPI
HCURSOR
WINAPI
LoadCursorW(
    _In_opt_ HINSTANCE hInstance,
    _In_ LPCWSTR lpCursorName);    //需要传入一个字符串
#ifdef UNICODE
#define LoadCursor  LoadCursorW

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qiuqiuyaq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值