title: SDK编程一
date: 2019-10-18 17:35:09
tags: SDK

categroies: 编程

第一个windows窗口程序

创建一个窗口程序的空项目,或者创建一个控制台空项目,调整下面的选项:

#include <Windows.h>

int WINAPI WinMain(
    HINSTANCE hInstance,    //实例句柄
    HINSTANCE hPreInstance, //没有用了
    LPSTR    szCmd,         //命令行参数
    int       nShow         //命令行参数
)
{
    MessageBox(0, L"你好", L"友情提示", 0);
    return 0;
}

在windows下编程,有两个问题需要提前了解:

1.在windows下,没有比较好用的输出数字的函数,我通常都需要自己转换:

int WINAPI WinMain(
    HINSTANCE hInstance,    //实例句柄
    HINSTANCE hPreInstance, //没有用了
    LPSTR    szCmd,         //命令行参数
    int       nShow         //命令行参数
)
{
    //想要将nNum的值,用MessageBox显示出来。
    //数字转字符串
    int nNum = 100;
    char buf[100] = {};
    sprintf_s(buf, "%d", nNum);

    MessageBoxA(0, buf, "友情提示", 0);
    return 0;
}

2.所有的字符串相关的API函数,都分成两个版本:A版和W版

int WINAPI WinMain(
    HINSTANCE hInstance,    //实例句柄
    HINSTANCE hPreInstance, //没有用了
    LPSTR    szCmd,         //命令行参数
    int       nShow         //命令行参数
)
{
    //想要将nNum的值,用MessageBox显示出来。
    //数字转字符串
    int nNum = 100;
    char buf[100] = {};
    wchar_t buf2[100] = {};
    sprintf_s(buf, "%d", nNum);
    swprintf_s(buf2, L"%d", nNum);


    MessageBoxA(0, buf, "友情提示", 0);

    MessageBoxW(0, buf2, L"友情提示", 0);
    return 0;
}

由于在我们使用的时候会有中文的情况,所以一般我们都使用T版函数

#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
int WINAPI WinMain(
    HINSTANCE hInstance,    //实例句柄
    HINSTANCE hPreInstance, //没有用了
    LPSTR    szCmd,         //命令行参数
    int       nShow         //命令行参数
)
{
    //想要将nNum的值,用MessageBox显示出来。
    //数字转字符串
    int nNum = 100;
    char buf[100] = {};
    wchar_t buf2[100] = {};
    sprintf_s(buf, "%d", nNum);
    swprintf_s(buf2, L"%d", nNum);
    MessageBoxA(0, buf, "友情提示", 0);
    MessageBoxW(0, buf2, L"友情提示", 0);
    
    //t版函数
    TCHAR buf3[100] = { _T("helloworld") };
    _stprintf_s(buf3, _T("%d"), nNum);
    MessageBox(0, buf3, _T("友情提示"), 0);

    return 0;
}

ascunicode之间的转换。

// 宽字符转换为多字符(Unicode --> ASCII)
#define  WCHAR_TO_CHAR(lpW_Char, lpChar) \
    WideCharToMultiByte(CP_ACP, NULL, lpW_Char, -1, 
            lpChar, _countof(lpChar), NULL, FALSE);


// 多字符转换为宽字符(ASCII --> Unicode)
#define  CHAR_TO_WCHAR(lpChar, lpW_Char) \
    MultiByteToWideChar(CP_ACP, NULL, lpChar, -1, 
            lpW_Char, _countof(lpW_Char));

在windows下输出调试信息:

bool _trace(const TCHAR *format, ...) //变参函数
{
    TCHAR buffer[1000];
    va_list argptr;
    va_start(argptr, format);
    //将格式化信息写入指定的缓冲区
    wvsprintf(buffer, format, argptr);
    va_end(argptr);
    //将缓冲区信息输出
    OutputDebugString(buffer);
    return true;
}


int WINAPI WinMain(
    HINSTANCE hInstance,    //实例句柄
    HINSTANCE hPreInstance, //没有用了
    LPSTR    szCmd,         //命令行参数
    int       nShow         //命令行参数
)
{
    int nNum = 100;

    _trace(_T("这个数字为%d"), nNum);

    return 0;
}


我们也可以自己封装带格式控制符的Messagebox

bool _MyMessageBox(const TCHAR *format, ...) //变参函数
{
    TCHAR buffer[1000];
    va_list argptr;
    va_start(argptr, format);
    //将格式化信息写入指定的缓冲区
    wvsprintf(buffer, format, argptr);
    va_end(argptr);
    //将缓冲区信息输出
    MessageBox(0,buffer,_T("提示"),0);
    return true;
}


int WINAPI WinMain(
    HINSTANCE hInstance,    //实例句柄
    HINSTANCE hPreInstance, //没有用了
    LPSTR    szCmd,         //命令行参数
    int       nShow         //命令行参数
)
{
    int nNum = 100;

    _MyMessageBox(_T("这个数字为%d"), nNum);

    return 0;
}

关于windows程序的错误码:

int WINAPI WinMain(
    HINSTANCE hInstance,    //实例句柄
    HINSTANCE hPreInstance, //没有用了
    LPSTR    szCmd,         //命令行参数
    int       nShow         //命令行参数
)
{
    HANDLE h = GetStdHandle(100);
    int nError = GetLastError();//这个函数能够获取到最近一次调用的API的错误码
    _MyMessageBox(_T("错误码为:%d"), nError);
    return 0;
}


在调试的时候,快速监视到错误码的方法:

制作一个能够解析错误码的工具,能够提供出错的具体位置:

#define  CHAR_TO_WCHAR(lpChar, lpW_Char) \
    MultiByteToWideChar(CP_ACP, NULL, lpChar, -1, \
lpW_Char, _countof(lpW_Char));


void MyGetErrorInfo(
    LPCTSTR lpErrInfo,
    UINT unErrCode,
    TCHAR* tFile,
    UINT unLine) // unLine=__LINE__
{
    LPTSTR lpMsgBuf = nullptr;
    WCHAR  szMessage[128] = { 0 };
    WCHAR  szCaption[128] = { 0 };

    //这个函数能够将错误码解析为错误信息
    FormatMessage(0x1300, NULL, unErrCode,
        0x400, (LPTSTR)&lpMsgBuf, 64, NULL);

    swprintf_s(szMessage, 128,
        L"Error_0x%08X:%s", unErrCode, lpMsgBuf);

    swprintf_s(szCaption, 128,
        L"%s:%s:(Error Line:%05d)", lpErrInfo, tFile, unLine);
    MessageBox(NULL, szCaption, szMessage , MB_OK);
}

int WINAPI WinMain(
    HINSTANCE hInstance,    //实例句柄
    HINSTANCE hPreInstance, //没有用了
    LPSTR    szCmd,         //命令行参数
    int       nShow         //命令行参数
)
{
    HANDLE h = GetStdHandle(100);
    //1 获得错误码
    int nError = GetLastError();
    //2 得到出错的文件路径
    wchar_t buf[100] = {};
    CHAR_TO_WCHAR(__FILE__, buf);
    //3 输出错误信息
    MyGetErrorInfo(_T("十五派友情提示您:"), nError, buf,__LINE__-1);
    return 0;
}

第一个窗口程序:

#include <Windows.h>
#include <tchar.h>
//int WinMain(
//  HINSTANCE hInstance,
//  HINSTANCE hPreInstance,
//  LPSTR    szCmd,
//  int       nShow
//);
//int wWinMain(
//  HINSTANCE hInstance,
//  HINSTANCE hPreInstance,
//  LPWSTR    szCmd,
//  int       nShow
//);


LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);


int WINAPI _tWinMain(
    HINSTANCE hInstance,
    HINSTANCE hPreInstance,
    LPTSTR    szCmd,
    int       nShow
)
{
    //1 设计窗口类
    //UINT        style;
    //WNDPROC     lpfnWndProc;
    //int         cbClsExtra;
    //int         cbWndExtra;
    //HINSTANCE   hInstance;
    //HICON       hIcon;
    //HCURSOR     hCursor;
    //HBRUSH      hbrBackground;
    //LPCWSTR     lpszMenuName;
    //LPCWSTR     lpszClassName;
    WNDCLASS wc;
    wc.style = CS_VREDRAW | CS_HREDRAW;//类风格
    wc.lpfnWndProc = WndProc;//回调函数的地址(重要)
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;//实例句柄,代表此程序
    wc.hIcon = 0;
    wc.hCursor = 0;
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = 0;
    wc.lpszClassName = L"15PB";

    //2 注册窗口类
    RegisterClass(&wc);
    //3 创建窗口
    HWND hWnd = CreateWindow(
        L"15PB",            //类名
        L"第一个窗口",       //窗口名
        WS_OVERLAPPEDWINDOW,//重叠窗口风格
        100, 100, 400, 600, //位置和大小
        NULL,               //父窗口句柄
        NULL,               //菜单句柄
        hInstance,          //实例句柄
        NULL                //附加信息
    );
    //4 更新显示窗口
    ShowWindow(hWnd, SW_SHOW);
    UpdateWindow(hWnd);
    //5  实现消息循环
    MSG msg = {};
    //  5.1 获取消息
    //GetMessage得到WM_QUIT消息的时候,会返回False
    while (GetMessage(&msg, 0, 0, 0))
    {
        //  5.2 转换消息 将WM_KEYDOWN转换WM_CHAR
        TranslateMessage(&msg);
        //  5.3 派发消息
        DispatchMessage(&msg);
    }

    return 0;
}



 LRESULT CALLBACK WndProc(
     HWND hWnd, 
     UINT uMessage, 
     WPARAM wParam,
     LPARAM lParam
 )
{
     switch (uMessage)
     {
     case WM_CLOSE:
         PostQuitMessage(0);//会发出一个WM_QUIT消息
         break;
     default:
         break;
     }
     return DefWindowProc(hWnd, uMessage, wParam, lParam);
}

常见的消息处理:
WM_CLOSE 窗口关闭的消息
WM_DESTORY 窗口销毁的消息
WM_KEYDOWN 键盘按下的消息
WM_CHAR 字符按键消息

WM_LBUTTONDOWN 鼠标左键单击消息
WM_MOVING 窗口移动消息
WM_SIZE 窗口大小改变的消息
需要用到的一个函数:GetClientRect 获取窗口的大小

 LRESULT CALLBACK WndProc(
     HWND hWnd, 
     UINT uMessage, 
     WPARAM wParam,
     LPARAM lParam
 )
{
     switch (uMessage)
     {
     case WM_CREATE://一般进行一些初始化的操作

         break;
     case WM_DESTROY:
         _trace(L"接到了wm_destory消息\n");
         PostQuitMessage(0);//会发出一个WM_QUIT消息
         break;
     case WM_CLOSE:
         _trace(L"接到了wm_close消息\n");
         break;
     case WM_KEYDOWN:
         _trace(L"接到了wm_keydown消息\n");
         _trace(L"lParam:%d,wParam:%d\n", lParam, wParam);
         break;
     case WM_CHAR://可见字符
         _trace(L"接到了wm_char消息\n");
         _trace(L"lParam:%d,wParam:%d\n", lParam, wParam);
         break;
     case WM_LBUTTONDOWN://鼠标左键单击
     {
         _trace(L"接到了wm_lbuttondown消息\n");
         int x = LOWORD(lParam);
         int y = HIWORD(lParam);
         _trace(L"鼠标左键点击了x:%d,y:%d\n",x,y);
     }
     case  WM_SIZE://窗口大小发生改变了
     {
         _trace(L"接到了wm_size消息\n");
         RECT rc = {};
        GetClientRect(hWnd,&rc);
         _trace(L"鼠标左键点击了l:%d,r:%d,t:%d,b:%d\n", 
             rc.left, rc.right,rc.top, rc.bottom);
     }
         break;
     default:
         break;
     }
     return DefWindowProc(hWnd, uMessage, wParam, lParam);
}

关于PostMessage,SendMessage,自定义消息

#define WM_MYMESSAGE WM_USER+2
 LRESULT CALLBACK WndProc(
     HWND hWnd, 
     UINT uMessage, 
     WPARAM wParam,
     LPARAM lParam
 )
{
     switch (uMessage)
     {
     case WM_CREATE://一般进行一些初始化的操作

         break;
     case WM_DESTROY:
         _trace(L"接到了wm_destory消息\n");
         PostQuitMessage(0);//会发出一个WM_QUIT消息
         break;
     case WM_CLOSE:
         _trace(L"接到了wm_close消息\n");
         break;
     case WM_KEYDOWN:
         _trace(L"接到了wm_keydown消息\n");
         _trace(L"lParam:%d,wParam:%d\n", lParam, wParam);
         break;
     case WM_CHAR://可见字符
         _trace(L"接到了wm_char消息\n");
         _trace(L"lParam:%d,wParam:%d\n", lParam, wParam);
         break;
     case WM_LBUTTONDOWN://鼠标左键单击
     {
         _trace(L"接到了wm_lbuttondown消息\n");
         int x = LOWORD(lParam);
         int y = HIWORD(lParam);
         _trace(L"鼠标左键点击了x:%d,y:%d\n",x,y);
     }
     case  WM_SIZE://窗口大小发生改变了
     {
         _trace(L"接到了wm_size消息\n");
         RECT rc = {};
        GetClientRect(hWnd,&rc);
         _trace(L"鼠标左键点击了l:%d,r:%d,t:%d,b:%d\n", 
             rc.left, rc.right,rc.top, rc.bottom);
     }
         break;
     case WM_MYMESSAGE:
     {

         _trace(L"接到了wm_mymessage消息\n");
         _trace(L"lParam:%d,wParam:%d\n", lParam, wParam);
         MessageBox(0, 0, 0, 0);
     }
         break;
     default:
         break;
     }
     return DefWindowProc(hWnd, uMessage, wParam, lParam);
}

消息泵处理消息

#define WM_MYMESSAGE WM_USER+2
int main()
{
    //FindWindow
    PostMessage(
        (HWND)0x00360E7C,
        WM_MYMESSAGE,
        68, 55
    );
}
最后修改:2020 年 08 月 26 日
如果觉得我的文章对你有用,请随意赞赏