Windows编程-001


  • 如果建立的是Win32控制台工程(入口函数是main函数)的话,WinMain函数不能作为入口函数,如果想要解决这个问题的话,可以打开项目属性->链接器->系统->子系统,把子系统对应的“控制台”改为“窗口”。

  • 名词释义:

  • API:应用程序编程接口(Aplication Programma Interface),是一组定义、程序及协议的集合是一些预先定义的接口(如函数、HTTP接口),或指软件系统不同组成部分衔接的约定。

  • SDK:软件开发包(Software Development Kit),SDK是一些被软件工程师用于为特定的软件包、软件框架、硬件平台、操作系统等创建应用软件的开发工具的集合。它可以简单的为某个程序设计语言提供应用程序接口API的一些文件,但也可能包括能与某种嵌入式系统通讯的复杂的硬件。SDK还经常包括示例代码、支持性的技术注解或者其他的为基本参考资料澄清疑点的支持文档。

  • 窗口:包含标题栏、菜单栏、系统菜单、最下化框,最大化框,滚动等,窗口主要分为客户区和非客户区;

  • 句柄:是一个标识符,是用来标识对象或者项目的。从数据类型上来看它只是一个16位的无符号整数。应用程序几乎总是通过调用一个Windows函数来获得一个句柄,之后其他的Windows函数就可以使用该句柄,以引用相应的对象。在 Windows编程中会用到大量的句柄。在 Windows程序中并不是用物理地址来标识一个内存块、文件、任务或动态装入模块的。相反地,Windows API给这些项目分配确定的句柄,并将句柄返回给应用程序,然后通过句柄来进行操作。

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

  • WINAPI:本质是__stdcall,(stdcall调用方式又被称作Pascal调用方式)是C/C++调用约定的一种,意思是函数的参数从右到左推送到栈上,被调用函数在返回之前从堆栈中弹出这些参数;

WINAPI可以看做是函数调用约定,约定了:

  1. 函数的入栈方式——从右往左

  1. 函数调用后,由谁来将堆栈恢复原状

  • WINAPICALLBACKAPIENTRY:从右往左入栈,本质都是__stdcall(标准调用方式);

WINAPIV:从右往左入栈,本质是__cdecel;

//转到定义,可以看到:
#define CALLBACK __stdcall
#define WINAPI __stdcall
#define WINAPIV __cdecl
#define APIENTRY WINAPI
  • C++函数调用的几种方式:

  1. stdcall

stdcall调用方式的函数声明为:int __stdcall function(int a,intb);

stdcall的调用方式意味着:

  1. 参数从右往左依次压入堆栈;

  1. 由被调用函数自己来恢复堆栈;

  1. 函数名自动加前导下划线,后面紧跟着一个@,其后紧跟着参数的尺寸。

上面函数翻译成汇编语言将变成:

push b先压入第二个参数

push a再压入第一个参数

call function调用函数

在编译时,此函数的名字翻译成_function@8

  1. cdecl

cdecl调用函数又称为C调用方式,是C语言缺省的调用方式,它的语法为:

int function(int a,int b)//不加修饰符就是C调用方式

int __cdecl function(int a,int b)//明确指定C调用方式

cdecel调用方式决定了:

  1. 参数从右向左依次压入堆栈;

  1. 由调用者恢复堆栈;

  1. 函数名自动加前导下划线。

由于是由调用者来恢复堆栈,因此C调用方式允许函数的参数个数是不固定的,这是C语言的一大特色。

此函数被翻译为:

push b //先压入第二个参数

push a //再压入第一个参数

call function // 调用函数

add esp, 8 //清理堆栈(此内容在汇编中esp寄存器的功能部分有讲)

在编译时,此方式的函数被翻译成:__function

  • 主函数参数:

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

//转到定义,看到本质为结构体指针:
DECLARE_HANDLE(HINSTANCE);
#define DECLARE_HANDLE(HINSTANCE)
struct HINSTANCE__
{
int unused;
};
typedef struct HINSTANCE__* HINSTANCE
  • hInstance :当前应用程序实例句柄;

  • hPreInstance:当前程序的前一个实例句柄,在32和64位机器上已废弃,现在不再使用,值为NULL,在16位机器上使用(任何一个基于GDI的Windows程序以WinMain函数作为入口被系统调用,在Win16中,hPreInstance指向程序的前一个实例句柄,但在Win32中,每一个进程都有一个独立的4G地址空间,从0到2G属于进程私有,对其他进程来说是不可见的。所以在Win32中,hPreInstance总是为NULL);

  • LPSTR:long point string;

typedef CHAR *NPSTR, *LPSTR, PSTR;
//上式表示 CHAR <=> NPSTR <=> LPSTR <=> PSTR
typedef char CHAR;
//LPSTR <=> char*
//LPCSTR <=> const char*
  • lpCmdLine:[in] Pointer to a null-terminated string specifying the command line for the application, excluding the program name. To retrieve the entire command line, use the GetCommandLine function.(指向一个应用程序命令中,除了程序名的null字符结束的字符串。GetCommandLine函数可以返回整个命令行)

lpCmdLine是一个以空终止的字符串,指定传递给应用程序的命令行参数。

  • nCmdShow:窗口显示方式(最大化,最小化,普通,正常显示);

  • MessageBox:Windows编程中经常用到的一个API,作用是弹出一个消息提示框;

int WINAPI MessageBox (
In_opt HWND hWnd,
In_opt LPCTSTR lpText,      //要在消息框中显示的文本
In_opt LPCTSTR lpCaption,   //对话框标题。如果为 NULL(默认值),则使用标题“错误”
In UINT uType       //指定对话框的内容和行为。有关可用不同消息框的列表,请参阅 Windows SDK 文档中的消息框条目。默认值提供一个简单的“确定”按钮。
);

第一个参数:

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

hWnd : 父窗口句柄,如果没有父窗口,就写NULL

HWND 本质为结构体指针

/*   HWND : 窗口句柄类型(可以理解为窗口的ID)
     hWnd : 父窗口句柄,如果没有父窗口,就写NULL
     HWND 本质为结构体指针                  */
DECLARE_HANDLE (HWND);
#define DECLARE_HANDLE(name) 
struct HWND__
{
  int unused;
};     
  typedef struct HWND__ *HWND
/*LPCTSTR:显示内容*/
//LPCTSTR在Unicode编码下
typedef LPCWSTR PCTSTR, LPCTSTR;          //LPCWSTR <=> PCTSTR <=> LPCTSTR
typedef  CONST WCHAR *LPCWSTR, *PCWSTR;   //CONST WCHAR* <=> LPCWSTR <=> PCWSTR
#define CONST               const         //CONST <=> const
typedef wchar_t WCHAR;                    //wchar_t <=> WCHAR
    //const wchar_t* <=>  LPCTSTR
//上述内容:LPCTSTR <=> const wchar_t*
/*LPSTR在多字节字符集情况下*/
typedef LPCTSTR PCTSTR, LPCTSTR;           //LPCTSTR  <=> PCTSTR <=> LPCTSTR
typedef  CONST CHAR *LPCWSTR, *PCWSTR;     //CONST CHAR* <=> LPCTSTR <=> PCWSTR
#define CONST const                        //CONST <=> const
typedef char CHAR;                         //char <=> CHAR
//上述内容:LPSTR <=> const char*
  • 实操

1.Hello World!

#include <Windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine , int nCmdShow)
{
    int n = MessageBox(NULL, L"Hello World!", L"温馨提示", MB_OK);
    if (n == IDOK)
    {
        MessageBox(NULL, L"点了OK", L"提示", MB_OK);
    }
    else if (n == IDNO)
    {
        MessageBox(NULL, L"点了No", L"提示", MB_OK);
    }
    else if (n == IDYES)
    {
        MessageBox(NULL, L"点了Yes", L"提示", MB_OK);
    }

    return 0;
}

2.FirstWindow

  • 流程:①设计窗口;②注册窗口;③创建窗口;④显示窗口;⑤更新窗口;⑥消息循环。

  • 窗口处理函数:

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

/*virtual LRESULT WindowProc(
   UINT message,        //message:指定要处理的Windows消息
   WPARAM wParam,       //wParam:提供用于处理的其他信息。参数值取决于消息
   LPARAM lParam        //lParam:提供用于处理消息的其他信息。参数值取决于消息
);
*/
  • 源代码

#include <Windows.h>
#include "resource.h"

//LRESULT:
//typedef LONG_PTR            LRESULT;   long

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

//第二个参数:消息编号   unsigned int

//第三个参数:WPARAM     unsigned int
//窗口附加信息

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


//窗口处理函数
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int nCmdShow)
{
    /*
    
    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;

    UINT
    
    */
    //UINT    //typedef unsigned int        UINT;

    //一、设计窗口类

    wchar_t szAppClassName[] = L"My_GUI";
    wchar_t szWindowName[] = L"这是我的第一个Windows程序";

    //LoadIcon
    //加载一个图标文件
    //第一个参数:应用程序实例句柄
    //如果是系统资源,传递NULL
    //如果是自定义资源,传递hInstance

    //第二个参数:资源ID


    //LoadCursor
    //加载一个光标文件
    //第一个参数:应用程序实例句柄
    //如果是系统资源,传递NULL
    //如果是自定义资源,传递hInstance

    //第二个参数:资源ID

    WNDCLASS wc;
    wc.style = CS_HREDRAW | CS_VREDRAW;            //窗口类的风格
    wc.lpfnWndProc = WindowProc;                //窗口处理函数
    wc.cbClsExtra = 0;                            //窗口类的额外扩展空间大小(字节)
    wc.cbWndExtra = 0;                            //窗口的额外扩展空间大小(字节)
    wc.hInstance = hInstance;                    //当前应用程序实例句柄
    wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_LOGO));                            //窗口图标句柄,NULL:没有图标
    wc.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR));                            //光标图标句柄
    wc.hbrBackground = CreateSolidBrush(RGB(255,255,255)); //背景画刷句柄, 0-》255,0:最暗;255:表示最亮  白色:RGB(255,255,255)  红色:RGB(255,0,0)
    wc.lpszMenuName = NULL;                        //菜单名
    wc.lpszClassName = szAppClassName;            //窗口类型名

    //二、注册窗口类
    //ATOM <= > WORD  <=> unsigned short 
    //DWORD  double WORD   
    //DWORD  <=> unsigned long

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

    //三、创建窗口
    HWND hWnd = CreateWindow(
        szAppClassName,                            //窗口类型名
        szWindowName,                            //窗口的标题
        WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,//窗口的风格
        200,                                    //窗口左上角横坐标
        200,                                    //窗口左上角纵坐标
        800,                                    //窗口的宽度
        600,                                    //窗口的高度
        NULL,                                    //父窗口句柄
        NULL,                                    //菜单句柄
        hInstance,                                //应用程序实力句柄
        NULL                                    //创建窗口需要传递的信息
        );

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

    //四、显示窗口
    ShowWindow(hWnd, SW_SHOW);

    //五、更新窗口
    UpdateWindow(hWnd);

    //六、消息循环

    /*
    typedef struct tagMSG {
    HWND        hwnd;                        //消息发给哪一个窗口的窗口句柄
    UINT        message;                    //消息编号,
    WPARAM      wParam;                        //附加信息
    LPARAM      lParam;                        //附加信息
    DWORD       time;                        //消息投放到消息队列里面的时间
    POINT       pt;                            //消息放入消息队列的时候鼠标的坐标
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;
    */
    
    //只要收到了 WM_QUIT消息,函数返回:0
    
    
    MSG msg;

    while (GetMessage(&msg, NULL, 0, 0))
    {
        //将虚拟键消息转为字符消息
        TranslateMessage(&msg);

        //将虚拟键消息分发给窗口处理函数
        DispatchMessage(&msg);
    }


    return 0;//程序退出了,结束了
}

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

    return DefWindowProc(hWnd, uMsg, wParam, lParam);//操作系统默认处理消息的函数
}

//Windows消息机制原理

猜你喜欢

转载自blog.csdn.net/qq_59470001/article/details/129287892
001