最近不想用MFC写东西了,有没有安装Qt和其他图形化开发环境,只能捣鼓API了。于是乎,就有了以下的学习–

首先,老套的创建个Windows窗口,由于自己有点小懒,就直接用Hello Word的源码了。

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

// 窗口过程函数
LRESULT CALLBACK WinSunProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

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(COLOR_WINDOW);    // 背景画刷句柄
    wndcls.hCursor = LoadCursor(NULL, IDC_ARROW);                   // 窗口光标句柄
    wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION);                       // 窗口图标句柄
    wndcls.hInstance = hInstance;                                   // 包含窗口过程函数的程序实例
    wndcls.lpfnWndProc = WinSunProc;                                // 只想窗口过程函数的指针
    wndcls.lpszClassName = "CRoot";                                // 窗口类名称
    wndcls.lpszMenuName = NULL;                                     // 菜单资源
    wndcls.style = CS_HREDRAW | CS_VREDRAW;                         // 窗口样式
    RegisterClass(&wndcls);

    // 创建窗口, 定义一个变量用来保存成功创建窗口后返回的句柄
    HWND hwnd;
    hwnd = CreateWindow(        // 窗口创建成功时返回为窗口分配的句柄 失败时返回NULL
        "CRoot",               // 窗口类名
        "Hello World",          // 窗口名字
        WS_CAPTION|WS_SYSMENU,    // 窗口样式
        CW_USEDEFAULT, CW_USEDEFAULT,                   // 窗口左上角坐标
        200, 120,               // 窗口宽高
        NULL,                   // 父窗口句柄
        NULL,                   // 窗口菜单句柄
        hInstance,              // 窗口所属应用程序实例
        NULL                    // WM_CREATE消息附加参数lParam传入的数据指针
        );

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

    // 定义消息结构体
    MSG msg;
    while (GetMessage(  // WM_QUIT消息返回0 错误返回-1
        &msg,           // 指向消息的结构体
        NULL,           // 指定接收属于哪一窗口的消息 通常设为NULL,用来接收属于调用线程的所有窗口的窗口消息
        0,              // 获取消息的最小值 通常为0
        0))             // 获取消息的最大值 都设为0表示接收所有消息
    {
        TranslateMessage(&msg);     // 将虚拟消息转换为字符消息 投递到调用线程的消息队列中 下次调用GetMessage时被取出
        DispatchMessage(&msg);      // 将消息传递给操作系统 由操作系统调用窗口过程函数对消息进行处理
    }
    return msg.wParam;
}

// 窗口过程函数
LRESULT CALLBACK WinSunProc(
    HWND hwnd,          // 窗口句柄
    UINT uMsg,          // 消息代码
    WPARAM wParam,      // 附加参数
    LPARAM lParam
)
{
    switch(uMsg)
    {
    case WM_CHAR:
        char szChar[20];
        sprintf(szChar, "char code is %d", wParam);
        MessageBox(hwnd, szChar, "char", 0);
        break;

    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

    return 0;
}

然后,我们要在消息循环里面添加创建Button的代码,因为Button是一个子窗口,所以创建方式也如同创建窗口一样,使用CreateWindow()函数。

而,此窗口要一开始跟随父窗口出现,所以要在父窗口创建时创建该Button。嗯,所以要在窗口过程函数里面监听下WM_CREATE消息。

代码片段:

 switch(uMsg)
    {
    case WM_CHAR:
        char szChar[20];
        sprintf(szChar, "char code is %d", wParam);
        MessageBox(hwnd, szChar, "char", 0);
        break;
    case WM_CREATE:
        CreateWindowEx(0,"Button","按钮1",WS_VISIBLE|WS_CHILD,0,0,100,50,hwnd,(HMENU)0,0,0);

    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

这里要说明一下啦,一开始我也搞得晕晕乎乎,不知道怎么搞Button的消息事件,这里我们用Button的ID啦。先看下微软的MSDN关于CreateWindow()函数

HWND WINAPI CreateWindow(
  _In_opt_  LPCTSTR lpClassName,
  _In_opt_  LPCTSTR lpWindowName,
  _In_      DWORD dwStyle,
  _In_      int x,
  _In_      int y,
  _In_      int nWidth,
  _In_      int nHeight,
  _In_opt_  HWND hWndParent,
  _In_opt_  HMENU hMenu,
  _In_opt_  HINSTANCE hInstance,
  _In_opt_  LPVOID lpParam
);

关键点在参数HMENU hWndParent,第一眼一看是不是感觉像菜单?不错啦~确实在菜单中用到的。进一步看他的解释

hMenu?[in, optional]

Type:?HMENU

A handle to a menu, or specifies a child-window identifier depending on the window style. For an overlapped or pop-up window,?hMenu?identifies the menu to be used with the window; it can be?NULL?if the class menu is to be used. For a child window,?hMenu?specifies the child-window identifier, an integer value used by a dialog box control to notify its parent about events. The application determines the child-window identifier; it must be unique for all child windows with the same parent window.

红色选中大体意思说,当在做一个子窗口的时候,这个参数就是一个整形表示,用于标识这个子窗口,提供父窗口的消息处理。总的来说就是所谓的控件ID啦~

既然有标识,就好办啦,我们就判断是不是他,若是这个按钮,我们就让他响应相应的操作啦~~

但是怎么知道按钮被Click了呢?我们又得监听另一个消息WM_COMMAND,它有两个参数,其中一个就传输了所谓的控件ID

wParam

For a description of this parameter.

lParam

For a description of this parameter.

我们可以判断他如果是这个按钮的ID,我们就让他干某些事情。我们首先要转换下wParam的类型,否则和我们写的ID的类型不一样的。

case WM_COMMAND:
wmId    = LOWORD(wParam); 
wmEvent = HIWORD(wParam);
     switch (wmId)
     {
         case (0)://之前我们创建按钮时,写的ID为0
//功能代码 //....... break; //...更多代码 }

好了,整体框架差不多完工啦,自己再加下代码啥的就没问题了。在这里,我再次浪费下篇幅,给出完整代码:

#include <windows.h>
 #include <stdio.h>
 #include <Windef.h>
 
 // 窗口过程函数
 LRESULT CALLBACK WinSunProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
 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(COLOR_WINDOW);    // 背景画刷句柄
     wndcls.hCursor = LoadCursor(NULL, IDC_ARROW);                   // 窗口光标句柄
     wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION);                       // 窗口图标句柄
     wndcls.hInstance = hInstance;                                   // 包含窗口过程函数的序实例
     wndcls.lpfnWndProc = WinSunProc;                                // 只想窗口过程函数的针
     wndcls.lpszClassName = "CRoot";                                // 窗口类名称
     wndcls.lpszMenuName = NULL;                                     // 菜单资源
     wndcls.style = CS_HREDRAW | CS_VREDRAW;                         // 窗口样式
     RegisterClass(&wndcls);
 
     // 创建窗口, 定义一个变量用来保存成功创建窗口后返回的句柄
     HWND hwnd;
     hwnd = CreateWindow(        // 窗口创建成功时返回为窗口分配的句柄 失败时返回NULL
         "CRoot",               // 窗口类名
         "Hello World",          // 窗口名字
         WS_CAPTION|WS_SYSMENU,    // 窗口样式
         CW_USEDEFAULT, CW_USEDEFAULT,                   // 窗口左上角坐标
         200, 120,               // 窗口宽高
         NULL,                   // 父窗口句柄
         NULL,                   // 窗口菜单句柄
         hInstance,              // 窗口所属应用程序实例
         NULL                    // WM_CREATE消息附加参数lParam传入的数据指针
         );
 
     // 显示及刷新窗口
     ShowWindow(hwnd, SW_SHOWNORMAL);
     UpdateWindow(hwnd);
 
     // 定义消息结构体
     MSG msg;
     while (GetMessage(  // WM_QUIT消息返回0 错误返回-1
         &msg,           // 指向消息的结构体
         NULL,           // 指定接收属于哪一窗口的消息 通常设为NULL,用来接收属于调用线程所有窗口的窗口消息
         0,              // 获取消息的最小值 通常为0
         0))             // 获取消息的最大值 都设为0表示接收所有消息
     {
         TranslateMessage(&msg);     // 将虚拟消息转换为字符消息 投递到调用线程的消息队列 下次调用GetMessage时被取出
         DispatchMessage(&msg);      // 将消息传递给操作系统 由操作系统调用窗口过程函数对息进行处理
     }
     return msg.wParam;
 }
 
 // 窗口过程函数
 LRESULT CALLBACK WinSunProc(
     HWND hwnd,          // 窗口句柄
     UINT uMsg,          // 消息代码
     WPARAM wParam,      // 附加参数
     LPARAM lParam
 )
 {
     WORD wmId    = LOWORD(wParam);
     //WORD wmEvent = HIWORD(wParam);
     switch(uMsg)
     {
     /*case WM_CHAR:
         char szChar[20];
         sprintf(szChar, "char code is %d", wParam);
         MessageBox(hwnd, szChar, "char", 0);
         break;*/
     case WM_CREATE:
         CreateWindowEx(0,"Button","按钮,WS_VISIBLE|WS_CHILD,0,0,70,40,hwnd,(HMENU)0,0,0);
         break;
     case WM_COMMAND:
         switch (wmId)
         {
             case 0://(HMENU) 和创建中的id对应
             //这里写你要让按钮实现的功能
                 MessageBoxA(NULL,"Hello Button!","My TestProject",MB_OK);
         }
         break;
 
     default:
         return DefWindowProc(hwnd, uMsg, wParam, lParam);
     }
 
     return 0;
 }

 

目前已经在GNU GCC Compiler成功!

 

页面下部广告

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

鲁ICP备17018668号-1